[FFmpeg-cvslog] lavfi: merge start_frame/draw_slice/end_frame

Anton Khirnov git at videolan.org
Thu Nov 29 02:52:01 CET 2012


ffmpeg | branch: master | Anton Khirnov <anton at khirnov.net> | Tue Nov 27 07:49:45 2012 +0100| [565e4993c63f797e2d50ad2f1e8f62fdbe299666] | committer: Anton Khirnov

lavfi: merge start_frame/draw_slice/end_frame

Any alleged performance benefits gained from the split are purely
mythological and do not justify added code complexity.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=565e4993c63f797e2d50ad2f1e8f62fdbe299666
---

 libavfilter/af_amix.c         |    6 +-
 libavfilter/af_ashowinfo.c    |    7 +-
 libavfilter/af_asyncts.c      |   10 +-
 libavfilter/af_channelmap.c   |    6 +-
 libavfilter/af_channelsplit.c |    6 +-
 libavfilter/af_join.c         |    6 +-
 libavfilter/af_resample.c     |   12 +--
 libavfilter/asink_anullsink.c |    4 +-
 libavfilter/audio.c           |   47 ---------
 libavfilter/audio.h           |   13 ---
 libavfilter/avfilter.c        |   69 ++++++++++++++
 libavfilter/avfilter.h        |   44 ++-------
 libavfilter/buffersink.c      |    7 +-
 libavfilter/buffersrc.c       |   15 +--
 libavfilter/fifo.c            |   43 ++-------
 libavfilter/internal.h        |   54 ++++-------
 libavfilter/split.c           |   64 ++-----------
 libavfilter/vf_aspect.c       |   13 +--
 libavfilter/vf_blackframe.c   |   30 ++----
 libavfilter/vf_boxblur.c      |   34 ++++---
 libavfilter/vf_copy.c         |    2 -
 libavfilter/vf_crop.c         |   65 ++++---------
 libavfilter/vf_cropdetect.c   |   28 +++---
 libavfilter/vf_delogo.c       |   46 +++++----
 libavfilter/vf_drawbox.c      |   19 ++--
 libavfilter/vf_drawtext.c     |   38 ++------
 libavfilter/vf_fade.c         |   29 ++----
 libavfilter/vf_fieldorder.c   |  114 ++++++----------------
 libavfilter/vf_format.c       |    6 --
 libavfilter/vf_fps.c          |   26 +----
 libavfilter/vf_frei0r.c       |   59 ++++--------
 libavfilter/vf_gradfun.c      |   47 +++++----
 libavfilter/vf_hflip.c        |   33 ++++---
 libavfilter/vf_hqdn3d.c       |   47 +++++----
 libavfilter/vf_libopencv.c    |   35 ++++---
 libavfilter/vf_lut.c          |   39 ++++----
 libavfilter/vf_null.c         |    2 -
 libavfilter/vf_overlay.c      |   34 ++-----
 libavfilter/vf_pad.c          |  151 ++++++++++-------------------
 libavfilter/vf_pixdesctest.c  |   65 +++++--------
 libavfilter/vf_scale.c        |   85 ++++-------------
 libavfilter/vf_select.c       |   52 +++-------
 libavfilter/vf_setpts.c       |   31 +++---
 libavfilter/vf_settb.c        |   14 ++-
 libavfilter/vf_showinfo.c     |   30 +++---
 libavfilter/vf_transpose.c    |   84 +++++++----------
 libavfilter/vf_unsharp.c      |   28 +++---
 libavfilter/vf_vflip.c        |   25 ++---
 libavfilter/vf_yadif.c        |   47 ++-------
 libavfilter/video.c           |  210 -----------------------------------------
 libavfilter/video.h           |   47 ---------
 libavfilter/vsink_nullsink.c  |   11 +--
 libavfilter/vsrc_color.c      |   23 +----
 libavfilter/vsrc_movie.c      |   20 +---
 libavfilter/vsrc_testsrc.c    |    8 +-
 55 files changed, 632 insertions(+), 1458 deletions(-)

diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c
index 7ef94b9..c2fb158 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -314,7 +314,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples)
     if (s->next_pts != AV_NOPTS_VALUE)
         s->next_pts += nb_samples;
 
-    return ff_filter_samples(outlink, out_buf);
+    return ff_filter_frame(outlink, out_buf);
 }
 
 /**
@@ -455,7 +455,7 @@ static int request_frame(AVFilterLink *outlink)
     return output_frame(outlink, available_samples);
 }
 
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     MixContext       *s = ctx->priv;
@@ -509,7 +509,7 @@ static int init(AVFilterContext *ctx, const char *args)
         snprintf(name, sizeof(name), "input%d", i);
         pad.type           = AVMEDIA_TYPE_AUDIO;
         pad.name           = av_strdup(name);
-        pad.filter_samples = filter_samples;
+        pad.filter_frame   = filter_frame;
 
         ff_insert_inpad(ctx, i, &pad);
     }
diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c
index bcf821a..c8e830e 100644
--- a/libavfilter/af_ashowinfo.c
+++ b/libavfilter/af_ashowinfo.c
@@ -34,6 +34,7 @@
 
 #include "audio.h"
 #include "avfilter.h"
+#include "internal.h"
 
 typedef struct AShowInfoContext {
     /**
@@ -64,7 +65,7 @@ static void uninit(AVFilterContext *ctx)
     av_freep(&s->plane_checksums);
 }
 
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     AShowInfoContext *s  = ctx->priv;
@@ -103,7 +104,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
     av_log(ctx, AV_LOG_INFO, "]\n");
 
     s->frame++;
-    return ff_filter_samples(inlink->dst->outputs[0], buf);
+    return ff_filter_frame(inlink->dst->outputs[0], buf);
 }
 
 static const AVFilterPad inputs[] = {
@@ -112,7 +113,7 @@ static const AVFilterPad inputs[] = {
         .type             = AVMEDIA_TYPE_AUDIO,
         .get_audio_buffer = ff_null_get_audio_buffer,
         .config_props     = config_input,
-        .filter_samples   = filter_samples,
+        .filter_frame     = filter_frame,
         .min_perms        = AV_PERM_READ,
     },
     { NULL },
diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c
index 94c5452..5d009f0 100644
--- a/libavfilter/af_asyncts.c
+++ b/libavfilter/af_asyncts.c
@@ -39,7 +39,7 @@ typedef struct ASyncContext {
     float min_delta_sec;
     int max_comp;
 
-    /* set by filter_samples() to signal an output frame to request_frame() */
+    /* set by filter_frame() to signal an output frame to request_frame() */
     int got_output;
 } ASyncContext;
 
@@ -141,7 +141,7 @@ static int request_frame(AVFilterLink *link)
         }
 
         buf->pts = s->pts;
-        return ff_filter_samples(link, buf);
+        return ff_filter_frame(link, buf);
     }
 
     return ret;
@@ -161,7 +161,7 @@ static int64_t get_delay(ASyncContext *s)
     return avresample_available(s->avr) + avresample_get_delay(s->avr);
 }
 
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     ASyncContext       *s = ctx->priv;
@@ -217,7 +217,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
             av_samples_set_silence(buf_out->extended_data, out_size - delta,
                                    delta, nb_channels, buf->format);
         }
-        ret = ff_filter_samples(outlink, buf_out);
+        ret = ff_filter_frame(outlink, buf_out);
         if (ret < 0)
             goto fail;
         s->got_output = 1;
@@ -243,7 +243,7 @@ static const AVFilterPad avfilter_af_asyncts_inputs[] = {
     {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
-        .filter_samples = filter_samples
+        .filter_frame   = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
index 4f9ee86..8b72d5b 100644
--- a/libavfilter/af_channelmap.c
+++ b/libavfilter/af_channelmap.c
@@ -313,7 +313,7 @@ static int channelmap_query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int channelmap_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -355,7 +355,7 @@ static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *bu
         memcpy(buf->data, buf->extended_data,
            FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
 
-    return ff_filter_samples(outlink, buf);
+    return ff_filter_frame(outlink, buf);
 }
 
 static int channelmap_config_input(AVFilterLink *inlink)
@@ -389,7 +389,7 @@ static const AVFilterPad avfilter_af_channelmap_inputs[] = {
     {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
-        .filter_samples = channelmap_filter_samples,
+        .filter_frame   = channelmap_filter_frame,
         .config_props   = channelmap_config_input
     },
     { NULL }
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index e8ceb9c..cc379f3 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -111,7 +111,7 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     int i, ret = 0;
@@ -128,7 +128,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
         buf_out->audio->channel_layout =
             av_channel_layout_extract_channel(buf->audio->channel_layout, i);
 
-        ret = ff_filter_samples(ctx->outputs[i], buf_out);
+        ret = ff_filter_frame(ctx->outputs[i], buf_out);
         if (ret < 0)
             break;
     }
@@ -140,7 +140,7 @@ static const AVFilterPad avfilter_af_channelsplit_inputs[] = {
     {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
-        .filter_samples = filter_samples,
+        .filter_frame   = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index c810e59..2b715d5 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -93,7 +93,7 @@ static const AVClass join_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
-static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf)
 {
     AVFilterContext *ctx = link->dst;
     JoinContext       *s = ctx->priv;
@@ -230,7 +230,7 @@ static int join_init(AVFilterContext *ctx, const char *args)
         snprintf(name, sizeof(name), "input%d", i);
         pad.type           = AVMEDIA_TYPE_AUDIO;
         pad.name           = av_strdup(name);
-        pad.filter_samples = filter_samples;
+        pad.filter_frame   = filter_frame;
 
         pad.needs_fifo = 1;
 
@@ -471,7 +471,7 @@ static int join_request_frame(AVFilterLink *outlink)
     priv->nb_in_buffers = ctx->nb_inputs;
     buf->buf->priv      = priv;
 
-    ret = ff_filter_samples(outlink, buf);
+    ret = ff_filter_frame(outlink, buf);
 
     memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);
 
diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c
index a0c7e0e..c712b46 100644
--- a/libavfilter/af_resample.c
+++ b/libavfilter/af_resample.c
@@ -40,7 +40,7 @@ typedef struct ResampleContext {
 
     int64_t next_pts;
 
-    /* set by filter_samples() to signal an output frame to request_frame() */
+    /* set by filter_frame() to signal an output frame to request_frame() */
     int got_output;
 } ResampleContext;
 
@@ -162,12 +162,12 @@ static int request_frame(AVFilterLink *outlink)
         }
 
         buf->pts = s->next_pts;
-        return ff_filter_samples(outlink, buf);
+        return ff_filter_frame(outlink, buf);
     }
     return ret;
 }
 
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     ResampleContext    *s = ctx->priv;
@@ -224,7 +224,7 @@ static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
 
             s->next_pts = buf_out->pts + buf_out->audio->nb_samples;
 
-            ret = ff_filter_samples(outlink, buf_out);
+            ret = ff_filter_frame(outlink, buf_out);
             s->got_output = 1;
         }
 
@@ -232,7 +232,7 @@ fail:
         avfilter_unref_buffer(buf);
     } else {
         buf->format = outlink->format;
-        ret = ff_filter_samples(outlink, buf);
+        ret = ff_filter_frame(outlink, buf);
         s->got_output = 1;
     }
 
@@ -243,7 +243,7 @@ static const AVFilterPad avfilter_af_resample_inputs[] = {
     {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
-        .filter_samples = filter_samples,
+        .filter_frame   = filter_frame,
         .min_perms      = AV_PERM_READ
     },
     { NULL }
diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c
index 397e745..ede54c0 100644
--- a/libavfilter/asink_anullsink.c
+++ b/libavfilter/asink_anullsink.c
@@ -20,7 +20,7 @@
 #include "avfilter.h"
 #include "internal.h"
 
-static int null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
+static int null_filter_frame(AVFilterLink *link, AVFilterBufferRef *samplesref)
 {
     avfilter_unref_bufferp(&samplesref);
     return 0;
@@ -30,7 +30,7 @@ static const AVFilterPad avfilter_asink_anullsink_inputs[] = {
     {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
-        .filter_samples = null_filter_samples,
+        .filter_frame   = null_filter_frame,
     },
     { NULL },
 };
diff --git a/libavfilter/audio.c b/libavfilter/audio.c
index 48e038b..bbe12b2 100644
--- a/libavfilter/audio.c
+++ b/libavfilter/audio.c
@@ -146,50 +146,3 @@ fail:
     av_freep(&samples);
     return NULL;
 }
-
-static int default_filter_samples(AVFilterLink *link,
-                                  AVFilterBufferRef *samplesref)
-{
-    return ff_filter_samples(link->dst->outputs[0], samplesref);
-}
-
-int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
-{
-    int (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
-    AVFilterPad *dst = link->dstpad;
-    AVFilterBufferRef *buf_out;
-
-    FF_DPRINTF_START(NULL, filter_samples); ff_dlog_link(NULL, link, 1);
-
-    if (!(filter_samples = dst->filter_samples))
-        filter_samples = default_filter_samples;
-
-    /* prepare to copy the samples if the buffer has insufficient permissions */
-    if ((dst->min_perms & samplesref->perms) != dst->min_perms ||
-        dst->rej_perms & samplesref->perms) {
-        av_log(link->dst, AV_LOG_DEBUG,
-               "Copying audio data in avfilter (have perms %x, need %x, reject %x)\n",
-               samplesref->perms, link->dstpad->min_perms, link->dstpad->rej_perms);
-
-        buf_out = ff_default_get_audio_buffer(link, dst->min_perms,
-                                              samplesref->audio->nb_samples);
-        if (!buf_out) {
-            avfilter_unref_buffer(samplesref);
-            return AVERROR(ENOMEM);
-        }
-        buf_out->pts                = samplesref->pts;
-        buf_out->audio->sample_rate = samplesref->audio->sample_rate;
-
-        /* Copy actual data into new samples buffer */
-        av_samples_copy(buf_out->extended_data, samplesref->extended_data,
-                        0, 0, samplesref->audio->nb_samples,
-                        av_get_channel_layout_nb_channels(link->channel_layout),
-                        link->format);
-
-        avfilter_unref_buffer(samplesref);
-    } else
-        buf_out = samplesref;
-
-    return filter_samples(link, buf_out);
-}
-
diff --git a/libavfilter/audio.h b/libavfilter/audio.h
index fa448e2..a377503 100644
--- a/libavfilter/audio.h
+++ b/libavfilter/audio.h
@@ -42,17 +42,4 @@ AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms,
 AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms,
                                              int nb_samples);
 
-/**
- * Send a buffer of audio samples to the next filter.
- *
- * @param link       the output link over which the audio samples are being sent
- * @param samplesref a reference to the buffer of audio samples being sent. The
- *                   receiving filter will free this reference when it no longer
- *                   needs it or pass it on to the next filter.
- *
- * @return >= 0 on success, a negative AVERROR on error. The receiving filter
- * is responsible for unreferencing samplesref in case of error.
- */
-int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
-
 #endif /* AVFILTER_AUDIO_H */
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index c7db857..93302cc 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -23,12 +23,16 @@
 
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
+#include "libavutil/imgutils.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/rational.h"
+#include "libavutil/samplefmt.h"
 
+#include "audio.h"
 #include "avfilter.h"
 #include "formats.h"
 #include "internal.h"
+#include "video.h"
 
 unsigned avfilter_version(void) {
     return LIBAVFILTER_VERSION_INT;
@@ -446,3 +450,68 @@ enum AVMediaType avfilter_pad_get_type(AVFilterPad *pads, int pad_idx)
 {
     return pads[pad_idx].type;
 }
+
+static int default_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+{
+    return ff_filter_frame(link->dst->outputs[0], frame);
+}
+
+int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+{
+    int (*filter_frame)(AVFilterLink *, AVFilterBufferRef *);
+    AVFilterPad *dst = link->dstpad;
+    AVFilterBufferRef *out;
+    int perms = frame->perms;
+
+    FF_DPRINTF_START(NULL, filter_frame);
+    ff_dlog_link(NULL, link, 1);
+
+    if (!(filter_frame = dst->filter_frame))
+        filter_frame = default_filter_frame;
+
+    if (frame->linesize[0] < 0)
+        perms |= AV_PERM_NEG_LINESIZES;
+    /* prepare to copy the frame if the buffer has insufficient permissions */
+    if ((dst->min_perms & perms) != dst->min_perms ||
+        dst->rej_perms & perms) {
+        av_log(link->dst, AV_LOG_DEBUG,
+               "Copying data in avfilter (have perms %x, need %x, reject %x)\n",
+               perms, link->dstpad->min_perms, link->dstpad->rej_perms);
+
+        switch (link->type) {
+        case AVMEDIA_TYPE_VIDEO:
+            out = ff_get_video_buffer(link, dst->min_perms,
+                                      link->w, link->h);
+            break;
+        case AVMEDIA_TYPE_AUDIO:
+            out = ff_get_audio_buffer(link, dst->min_perms,
+                                      frame->audio->nb_samples);
+            break;
+        default: return AVERROR(EINVAL);
+        }
+        if (!out) {
+            avfilter_unref_buffer(frame);
+            return AVERROR(ENOMEM);
+        }
+        avfilter_copy_buffer_ref_props(out, frame);
+
+        switch (link->type) {
+        case AVMEDIA_TYPE_VIDEO:
+            av_image_copy(out->data, out->linesize, frame->data, frame->linesize,
+                          frame->format, frame->video->w, frame->video->h);
+            break;
+        case AVMEDIA_TYPE_AUDIO:
+            av_samples_copy(out->extended_data, frame->extended_data,
+                            0, 0, frame->audio->nb_samples,
+                            av_get_channel_layout_nb_channels(frame->audio->channel_layout),
+                            frame->format);
+            break;
+        default: return AVERROR(EINVAL);
+        }
+
+        avfilter_unref_buffer(frame);
+    } else
+        out = frame;
+
+    return filter_frame(link, out);
+}
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 01d39b6..c5f8d56 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -253,14 +253,7 @@ struct AVFilterPad {
     int rej_perms;
 
     /**
-     * Callback called before passing the first slice of a new frame. If
-     * NULL, the filter layer will default to storing a reference to the
-     * picture inside the link structure.
-     *
-     * Input video pads only.
-     *
-     * @return >= 0 on success, a negative AVERROR on error. picref will be
-     * unreferenced by the caller in case of error.
+     * @deprecated unused
      */
     int (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref);
 
@@ -282,37 +275,26 @@ struct AVFilterPad {
                                            int nb_samples);
 
     /**
-     * Callback called after the slices of a frame are completely sent. If
-     * NULL, the filter layer will default to releasing the reference stored
-     * in the link structure during start_frame().
-     *
-     * Input video pads only.
-     *
-     * @return >= 0 on success, a negative AVERROR on error.
+     * @deprecated unused
      */
     int (*end_frame)(AVFilterLink *link);
 
     /**
-     * Slice drawing callback. This is where a filter receives video data
-     * and should do its processing.
-     *
-     * Input video pads only.
-     *
-     * @return >= 0 on success, a negative AVERROR on error.
+     * @deprecated unused
      */
     int (*draw_slice)(AVFilterLink *link, int y, int height, int slice_dir);
 
     /**
-     * Samples filtering callback. This is where a filter receives audio data
-     * and should do its processing.
+     * Filtering callback. This is where a filter receives a frame with
+     * audio/video data and should do its processing.
      *
-     * Input audio pads only.
+     * Input pads only.
      *
      * @return >= 0 on success, a negative AVERROR on error. This function
      * must ensure that samplesref is properly unreferenced on error if it
      * hasn't been passed on to another filter.
      */
-    int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref);
+    int (*filter_frame)(AVFilterLink *link, AVFilterBufferRef *frame);
 
     /**
      * Frame poll callback. This returns the number of immediately available
@@ -531,18 +513,6 @@ struct AVFilterLink {
         AVLINK_STARTINIT,       ///< started, but incomplete
         AVLINK_INIT             ///< complete
     } init_state;
-
-    /**
-     * The buffer reference currently being sent across the link by the source
-     * filter. This is used internally by the filter system to allow
-     * automatic copying of buffers which do not have sufficient permissions
-     * for the destination. This should not be accessed directly by the
-     * filters.
-     */
-    AVFilterBufferRef *src_buf;
-
-    AVFilterBufferRef *cur_buf;
-    AVFilterBufferRef *out_buf;
 };
 
 /**
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 96f5351..a315cb3 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -48,13 +48,12 @@ static av_cold void uninit(AVFilterContext *ctx)
         av_audio_fifo_free(sink->audio_fifo);
 }
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf)
 {
     BufferSinkContext *s = link->dst->priv;
 
     av_assert0(!s->cur_buf);
     s->cur_buf    = buf;
-    link->cur_buf = NULL;
 
     return 0;
 }
@@ -144,7 +143,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
     {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
-        .start_frame = start_frame,
+        .filter_frame = filter_frame,
         .min_perms   = AV_PERM_READ,
         .needs_fifo  = 1
     },
@@ -165,7 +164,7 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
     {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
-        .filter_samples = start_frame,
+        .filter_frame   = filter_frame,
         .min_perms      = AV_PERM_READ,
         .needs_fifo     = 1
     },
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 9354691..3cee68d 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -327,20 +327,7 @@ static int request_frame(AVFilterLink *link)
     }
     av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
 
-    switch (link->type) {
-    case AVMEDIA_TYPE_VIDEO:
-        if ((ret = ff_start_frame(link, buf)) < 0 ||
-            (ret = ff_draw_slice(link, 0, link->h, 1)) < 0 ||
-            (ret = ff_end_frame(link)) < 0)
-            return ret;
-        break;
-    case AVMEDIA_TYPE_AUDIO:
-        ret = ff_filter_samples(link, buf);
-        break;
-    default:
-        avfilter_unref_bufferp(&buf);
-        return AVERROR(EINVAL);
-    }
+    ff_filter_frame(link, buf);
 
     return ret;
 }
diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c
index 1bfacaf..88c44fe 100644
--- a/libavfilter/fifo.c
+++ b/libavfilter/fifo.c
@@ -77,7 +77,6 @@ static int add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     FifoContext *fifo = inlink->dst->priv;
 
-    inlink->cur_buf = NULL;
     fifo->last->next = av_mallocz(sizeof(Buf));
     if (!fifo->last->next) {
         avfilter_unref_buffer(buf);
@@ -99,16 +98,6 @@ static void queue_pop(FifoContext *s)
     s->root.next = tmp;
 }
 
-static int end_frame(AVFilterLink *inlink)
-{
-    return 0;
-}
-
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
 /**
  * Move data pointers and pts offset samples forward.
  */
@@ -228,7 +217,7 @@ static int return_audio_frame(AVFilterContext *ctx)
         buf_out = s->buf_out;
         s->buf_out = NULL;
     }
-    return ff_filter_samples(link, buf_out);
+    return ff_filter_frame(link, buf_out);
 }
 
 static int request_frame(AVFilterLink *outlink)
@@ -241,27 +230,11 @@ static int request_frame(AVFilterLink *outlink)
             return ret;
     }
 
-    /* by doing this, we give ownership of the reference to the next filter,
-     * so we don't have to worry about dereferencing it ourselves. */
-    switch (outlink->type) {
-    case AVMEDIA_TYPE_VIDEO:
-        if ((ret = ff_start_frame(outlink, fifo->root.next->buf)) < 0 ||
-            (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
-            (ret = ff_end_frame(outlink)) < 0)
-            return ret;
-
+    if (outlink->request_samples) {
+        return return_audio_frame(outlink->src);
+    } else {
+        ret = ff_filter_frame(outlink, fifo->root.next->buf);
         queue_pop(fifo);
-        break;
-    case AVMEDIA_TYPE_AUDIO:
-        if (outlink->request_samples) {
-            return return_audio_frame(outlink->src);
-        } else {
-            ret = ff_filter_samples(outlink, fifo->root.next->buf);
-            queue_pop(fifo);
-        }
-        break;
-    default:
-        return AVERROR(EINVAL);
     }
 
     return ret;
@@ -272,9 +245,7 @@ static const AVFilterPad avfilter_vf_fifo_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = add_to_queue,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = add_to_queue,
         .rej_perms        = AV_PERM_REUSE2,
     },
     { NULL }
@@ -307,7 +278,7 @@ static const AVFilterPad avfilter_af_afifo_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_AUDIO,
         .get_audio_buffer = ff_null_get_audio_buffer,
-        .filter_samples   = add_to_queue,
+        .filter_frame     = add_to_queue,
         .rej_perms        = AV_PERM_REUSE2,
     },
     { NULL }
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 6f868ae..216a355 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -64,18 +64,6 @@ struct AVFilterPad {
     int rej_perms;
 
     /**
-     * Callback called before passing the first slice of a new frame. If
-     * NULL, the filter layer will default to storing a reference to the
-     * picture inside the link structure.
-     *
-     * Input video pads only.
-     *
-     * @return >= 0 on success, a negative AVERROR on error. picref will be
-     * unreferenced by the caller in case of error.
-     */
-    void (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref);
-
-    /**
      * Callback function to get a video buffer. If NULL, the filter system will
      * use avfilter_default_get_video_buffer().
      *
@@ -93,37 +81,16 @@ struct AVFilterPad {
                                            int nb_samples);
 
     /**
-     * Callback called after the slices of a frame are completely sent. If
-     * NULL, the filter layer will default to releasing the reference stored
-     * in the link structure during start_frame().
+     * Filtering callback. This is where a filter receives a frame with
+     * audio/video data and should do its processing.
      *
-     * Input video pads only.
-     *
-     * @return >= 0 on success, a negative AVERROR on error.
-     */
-    int (*end_frame)(AVFilterLink *link);
-
-    /**
-     * Slice drawing callback. This is where a filter receives video data
-     * and should do its processing.
-     *
-     * Input video pads only.
-     *
-     * @return >= 0 on success, a negative AVERROR on error.
-     */
-    int (*draw_slice)(AVFilterLink *link, int y, int height, int slice_dir);
-
-    /**
-     * Samples filtering callback. This is where a filter receives audio data
-     * and should do its processing.
-     *
-     * Input audio pads only.
+     * Input pads only.
      *
      * @return >= 0 on success, a negative AVERROR on error. This function
      * must ensure that samplesref is properly unreferenced on error if it
      * hasn't been passed on to another filter.
      */
-    int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref);
+    int (*filter_frame)(AVFilterLink *link, AVFilterBufferRef *frame);
 
     /**
      * Frame poll callback. This returns the number of immediately available
@@ -237,4 +204,17 @@ int ff_poll_frame(AVFilterLink *link);
  */
 int ff_request_frame(AVFilterLink *link);
 
+/**
+ * Send a frame of data to the next filter.
+ *
+ * @param link   the output link over which the data is being sent
+ * @param frame a reference to the buffer of data being sent. The
+ *              receiving filter will free this reference when it no longer
+ *              needs it or pass it on to the next filter.
+ *
+ * @return >= 0 on success, a negative AVERROR on error. The receiving filter
+ * is responsible for unreferencing frame in case of error.
+ */
+int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame);
+
 #endif /* AVFILTER_INTERNAL_H */
diff --git a/libavfilter/split.c b/libavfilter/split.c
index 01bb448..c1e1669 100644
--- a/libavfilter/split.c
+++ b/libavfilter/split.c
@@ -67,46 +67,23 @@ static void split_uninit(AVFilterContext *ctx)
         av_freep(&ctx->output_pads[i].name);
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     int i, ret = 0;
 
     for (i = 0; i < ctx->nb_outputs; i++) {
-        AVFilterBufferRef *buf_out = avfilter_ref_buffer(picref, ~AV_PERM_WRITE);
-        if (!buf_out)
-            return AVERROR(ENOMEM);
-
-        ret = ff_start_frame(ctx->outputs[i], buf_out);
-        if (ret < 0)
-            break;
-    }
-    return ret;
-}
-
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    AVFilterContext *ctx = inlink->dst;
-    int i, ret = 0;
-
-    for (i = 0; i < ctx->nb_outputs; i++) {
-        ret = ff_draw_slice(ctx->outputs[i], y, h, slice_dir);
-        if (ret < 0)
+        AVFilterBufferRef *buf_out = avfilter_ref_buffer(frame, ~AV_PERM_WRITE);
+        if (!buf_out) {
+            ret = AVERROR(ENOMEM);
             break;
-    }
-    return ret;
-}
-
-static int end_frame(AVFilterLink *inlink)
-{
-    AVFilterContext *ctx = inlink->dst;
-    int i, ret = 0;
+        }
 
-    for (i = 0; i < ctx->nb_outputs; i++) {
-        ret = ff_end_frame(ctx->outputs[i]);
+        ret = ff_filter_frame(ctx->outputs[i], buf_out);
         if (ret < 0)
             break;
     }
+    avfilter_unref_bufferp(&frame);
     return ret;
 }
 
@@ -115,9 +92,7 @@ static const AVFilterPad avfilter_vf_split_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = start_frame,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
@@ -133,33 +108,12 @@ AVFilter avfilter_vf_split = {
     .outputs   = NULL,
 };
 
-static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
-{
-    AVFilterContext *ctx = inlink->dst;
-    int i, ret = 0;
-
-    for (i = 0; i < ctx->nb_outputs; i++) {
-        AVFilterBufferRef *buf_out = avfilter_ref_buffer(samplesref,
-                                                         ~AV_PERM_WRITE);
-        if (!buf_out) {
-            ret = AVERROR(ENOMEM);
-            break;
-        }
-
-        ret = ff_filter_samples(inlink->dst->outputs[i], buf_out);
-        if (ret < 0)
-            break;
-    }
-    avfilter_unref_buffer(samplesref);
-    return ret;
-}
-
 static const AVFilterPad avfilter_af_asplit_inputs[] = {
     {
         .name             = "default",
         .type             = AVMEDIA_TYPE_AUDIO,
         .get_audio_buffer = ff_null_get_audio_buffer,
-        .filter_samples   = filter_samples
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c
index 9f0c0c0..d7e851c 100644
--- a/libavfilter/vf_aspect.c
+++ b/libavfilter/vf_aspect.c
@@ -65,13 +65,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
 {
     AspectContext *aspect = link->dst->priv;
 
-    picref->video->pixel_aspect = aspect->aspect;
-    link->cur_buf = NULL;
-    return ff_start_frame(link->dst->outputs[0], picref);
+    frame->video->pixel_aspect = aspect->aspect;
+    return ff_filter_frame(link->dst->outputs[0], frame);
 }
 
 #if CONFIG_SETDAR_FILTER
@@ -99,8 +98,7 @@ static const AVFilterPad avfilter_vf_setdar_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = setdar_config_props,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = start_frame,
-        .end_frame        = ff_null_end_frame
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
@@ -144,8 +142,7 @@ static const AVFilterPad avfilter_vf_setsar_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = setsar_config_props,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = start_frame,
-        .end_frame        = ff_null_end_frame
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_blackframe.c b/libavfilter/vf_blackframe.c
index 9a27b69..275ebb2 100644
--- a/libavfilter/vf_blackframe.c
+++ b/libavfilter/vf_blackframe.c
@@ -78,49 +78,37 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     BlackFrameContext *blackframe = ctx->priv;
-    AVFilterBufferRef *picref = inlink->cur_buf;
     int x, i;
-    uint8_t *p = picref->data[0] + y * picref->linesize[0];
+    int pblack = 0;
+    uint8_t *p = frame->data[0];
 
-    for (i = 0; i < h; i++) {
+    for (i = 0; i < frame->video->h; i++) {
         for (x = 0; x < inlink->w; x++)
             blackframe->nblack += p[x] < blackframe->bthresh;
-        p += picref->linesize[0];
+        p += frame->linesize[0];
     }
 
-    return ff_draw_slice(ctx->outputs[0], y, h, slice_dir);
-}
-
-static int end_frame(AVFilterLink *inlink)
-{
-    AVFilterContext *ctx = inlink->dst;
-    BlackFrameContext *blackframe = ctx->priv;
-    AVFilterBufferRef *picref = inlink->cur_buf;
-    int pblack = 0;
-
     pblack = blackframe->nblack * 100 / (inlink->w * inlink->h);
     if (pblack >= blackframe->bamount)
         av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pos:%"PRId64" pts:%"PRId64" t:%f\n",
-               blackframe->frame, pblack, picref->pos, picref->pts,
-               picref->pts == AV_NOPTS_VALUE ? -1 : picref->pts * av_q2d(inlink->time_base));
+               blackframe->frame, pblack, frame->pos, frame->pts,
+               frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base));
 
     blackframe->frame++;
     blackframe->nblack = 0;
-    return ff_end_frame(inlink->dst->outputs[0]);
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_blackframe_inputs[] = {
     {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
-        .draw_slice       = draw_slice,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c
index 755d98e..d72c602 100644
--- a/libavfilter/vf_boxblur.c
+++ b/libavfilter/vf_boxblur.c
@@ -307,31 +307,39 @@ static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li
                    h, radius, power, temp);
 }
 
-static int draw_slice(AVFilterLink *inlink, int y0, int h0, int slice_dir)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     AVFilterContext *ctx = inlink->dst;
     BoxBlurContext *boxblur = ctx->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *inpicref  = inlink ->cur_buf;
-    AVFilterBufferRef *outpicref = outlink->out_buf;
+    AVFilterBufferRef *out;
     int plane;
-    int cw = inlink->w >> boxblur->hsub, ch = h0 >> boxblur->vsub;
+    int cw = inlink->w >> boxblur->hsub, ch = in->video->h >> boxblur->vsub;
     int w[4] = { inlink->w, cw, cw, inlink->w };
-    int h[4] = { h0, ch, ch, h0 };
+    int h[4] = { in->video->h, ch, ch, in->video->h };
 
-    for (plane = 0; inpicref->data[plane] && plane < 4; plane++)
-        hblur(outpicref->data[plane], outpicref->linesize[plane],
-              inpicref ->data[plane], inpicref ->linesize[plane],
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
+        return AVERROR(ENOMEM);
+    }
+    avfilter_copy_buffer_ref_props(out, in);
+
+    for (plane = 0; in->data[plane] && plane < 4; plane++)
+        hblur(out->data[plane], out->linesize[plane],
+              in ->data[plane], in ->linesize[plane],
               w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane],
               boxblur->temp);
 
-    for (plane = 0; inpicref->data[plane] && plane < 4; plane++)
-        vblur(outpicref->data[plane], outpicref->linesize[plane],
-              outpicref->data[plane], outpicref->linesize[plane],
+    for (plane = 0; in->data[plane] && plane < 4; plane++)
+        vblur(out->data[plane], out->linesize[plane],
+              out->data[plane], out->linesize[plane],
               w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane],
               boxblur->temp);
 
-    return ff_draw_slice(outlink, y0, h0, slice_dir);
+    avfilter_unref_bufferp(&in);
+
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
@@ -339,7 +347,7 @@ static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
-        .draw_slice   = draw_slice,
+        .filter_frame = filter_frame,
         .min_perms    = AV_PERM_READ
     },
     { NULL }
diff --git a/libavfilter/vf_copy.c b/libavfilter/vf_copy.c
index a20da93..8ece5cf 100644
--- a/libavfilter/vf_copy.c
+++ b/libavfilter/vf_copy.c
@@ -31,8 +31,6 @@ static const AVFilterPad avfilter_vf_copy_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .end_frame        = ff_null_end_frame,
         .rej_perms        = ~0
     },
     { NULL }
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index f79f574..981dfd6 100644
--- a/libavfilter/vf_crop.c
+++ b/libavfilter/vf_crop.c
@@ -243,24 +243,19 @@ static int config_output(AVFilterLink *link)
     return 0;
 }
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = link->dst;
     CropContext *crop = ctx->priv;
-    AVFilterBufferRef *ref2;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
     int i;
 
-    ref2 = avfilter_ref_buffer(picref, ~0);
-    if (!ref2)
-        return AVERROR(ENOMEM);
+    frame->video->w = crop->w;
+    frame->video->h = crop->h;
 
-    ref2->video->w = crop->w;
-    ref2->video->h = crop->h;
-
-    crop->var_values[VAR_T] = picref->pts == AV_NOPTS_VALUE ?
-        NAN : picref->pts * av_q2d(link->time_base);
-    crop->var_values[VAR_POS] = picref->pos == -1 ? NAN : picref->pos;
+    crop->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
+        NAN : frame->pts * av_q2d(link->time_base);
+    crop->var_values[VAR_POS] = frame->pos == -1 ? NAN : frame->pos;
     crop->var_values[VAR_X] = av_expr_eval(crop->x_pexpr, crop->var_values, NULL);
     crop->var_values[VAR_Y] = av_expr_eval(crop->y_pexpr, crop->var_values, NULL);
     crop->var_values[VAR_X] = av_expr_eval(crop->x_pexpr, crop->var_values, NULL);
@@ -279,60 +274,34 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
             (int)crop->var_values[VAR_N], crop->var_values[VAR_T], crop->x,
             crop->y, crop->x+crop->w, crop->y+crop->h);
 
-    ref2->data[0] += crop->y * ref2->linesize[0];
-    ref2->data[0] += crop->x * crop->max_step[0];
+    frame->data[0] += crop->y * frame->linesize[0];
+    frame->data[0] += crop->x * crop->max_step[0];
 
     if (!(desc->flags & PIX_FMT_PAL || desc->flags & PIX_FMT_PSEUDOPAL)) {
         for (i = 1; i < 3; i ++) {
-            if (ref2->data[i]) {
-                ref2->data[i] += (crop->y >> crop->vsub) * ref2->linesize[i];
-                ref2->data[i] += (crop->x * crop->max_step[i]) >> crop->hsub;
+            if (frame->data[i]) {
+                frame->data[i] += (crop->y >> crop->vsub) * frame->linesize[i];
+                frame->data[i] += (crop->x * crop->max_step[i]) >> crop->hsub;
             }
         }
     }
 
     /* alpha plane */
-    if (ref2->data[3]) {
-        ref2->data[3] += crop->y * ref2->linesize[3];
-        ref2->data[3] += crop->x * crop->max_step[3];
+    if (frame->data[3]) {
+        frame->data[3] += crop->y * frame->linesize[3];
+        frame->data[3] += crop->x * crop->max_step[3];
     }
 
-    return ff_start_frame(link->dst->outputs[0], ref2);
-}
-
-static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    AVFilterContext *ctx = link->dst;
-    CropContext *crop = ctx->priv;
-
-    if (y >= crop->y + crop->h || y + h <= crop->y)
-        return 0;
-
-    if (y < crop->y) {
-        h -= crop->y - y;
-        y  = crop->y;
-    }
-    if (y + h > crop->y + crop->h)
-        h = crop->y + crop->h - y;
-
-    return ff_draw_slice(ctx->outputs[0], y - crop->y, h, slice_dir);
-}
-
-static int end_frame(AVFilterLink *link)
-{
-    CropContext *crop = link->dst->priv;
-
     crop->var_values[VAR_N] += 1.0;
-    return ff_end_frame(link->dst->outputs[0]);
+
+    return ff_filter_frame(link->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_crop_inputs[] = {
     {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
-        .start_frame      = start_frame,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
         .get_video_buffer = ff_null_get_video_buffer,
         .config_props     = config_input,
     },
diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 63a72cb..eebd8bc 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -117,11 +117,10 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     CropDetectContext *cd = ctx->priv;
-    AVFilterBufferRef *picref = inlink->cur_buf;
     int bpp = cd->max_pixsteps[0];
     int w, h, x, y, shrink_by;
 
@@ -129,36 +128,36 @@ static int end_frame(AVFilterLink *inlink)
     if (++cd->frame_nb > 0) {
         // Reset the crop area every reset_count frames, if reset_count is > 0
         if (cd->reset_count > 0 && cd->frame_nb > cd->reset_count) {
-            cd->x1 = picref->video->w-1;
-            cd->y1 = picref->video->h-1;
+            cd->x1 = frame->video->w-1;
+            cd->y1 = frame->video->h-1;
             cd->x2 = 0;
             cd->y2 = 0;
             cd->frame_nb = 1;
         }
 
         for (y = 0; y < cd->y1; y++) {
-            if (checkline(ctx, picref->data[0] + picref->linesize[0] * y, bpp, picref->video->w, bpp) > cd->limit) {
+            if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) {
                 cd->y1 = y;
                 break;
             }
         }
 
-        for (y = picref->video->h-1; y > cd->y2; y--) {
-            if (checkline(ctx, picref->data[0] + picref->linesize[0] * y, bpp, picref->video->w, bpp) > cd->limit) {
+        for (y = frame->video->h-1; y > cd->y2; y--) {
+            if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) {
                 cd->y2 = y;
                 break;
             }
         }
 
         for (y = 0; y < cd->x1; y++) {
-            if (checkline(ctx, picref->data[0] + bpp*y, picref->linesize[0], picref->video->h, bpp) > cd->limit) {
+            if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) {
                 cd->x1 = y;
                 break;
             }
         }
 
-        for (y = picref->video->w-1; y > cd->x2; y--) {
-            if (checkline(ctx, picref->data[0] + bpp*y, picref->linesize[0], picref->video->h, bpp) > cd->limit) {
+        for (y = frame->video->w-1; y > cd->x2; y--) {
+            if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) {
                 cd->x2 = y;
                 break;
             }
@@ -189,12 +188,12 @@ static int end_frame(AVFilterLink *inlink)
 
         av_log(ctx, AV_LOG_INFO,
                "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pos:%"PRId64" pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
-               cd->x1, cd->x2, cd->y1, cd->y2, w, h, x, y, picref->pos, picref->pts,
-               picref->pts == AV_NOPTS_VALUE ? -1 : picref->pts * av_q2d(inlink->time_base),
+               cd->x1, cd->x2, cd->y1, cd->y2, w, h, x, y, frame->pos, frame->pts,
+               frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
                w, h, x, y);
     }
 
-    return ff_end_frame(inlink->dst->outputs[0]);
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_cropdetect_inputs[] = {
@@ -203,8 +202,7 @@ static const AVFilterPad avfilter_vf_cropdetect_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c
index 361e0b7..76848c3 100644
--- a/libavfilter/vf_delogo.c
+++ b/libavfilter/vf_delogo.c
@@ -215,30 +215,38 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     DelogoContext *delogo = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *inpicref  = inlink ->cur_buf;
-    AVFilterBufferRef *outpicref = outlink->out_buf;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
-    int direct = inpicref->buf == outpicref->buf;
+    AVFilterBufferRef *out;
     int hsub0 = desc->log2_chroma_w;
     int vsub0 = desc->log2_chroma_h;
+    int direct;
     int plane;
-    int ret;
 
-    for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) {
+    if ((in->perms & AV_PERM_WRITE) && !(in->perms & AV_PERM_PRESERVE)) {
+        direct = 1;
+        out = in;
+    } else {
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        if (!out) {
+            avfilter_unref_bufferp(&in);
+            return AVERROR(ENOMEM);
+        }
+
+        avfilter_copy_buffer_ref_props(out, in);
+        out->video->w = outlink->w;
+        out->video->h = outlink->h;
+    }
+
+    for (plane = 0; plane < 4 && in->data[plane]; plane++) {
         int hsub = plane == 1 || plane == 2 ? hsub0 : 0;
         int vsub = plane == 1 || plane == 2 ? vsub0 : 0;
 
-        apply_delogo(outpicref->data[plane], outpicref->linesize[plane],
-                     inpicref ->data[plane], inpicref ->linesize[plane],
+        apply_delogo(out->data[plane], out->linesize[plane],
+                     in ->data[plane], in ->linesize[plane],
                      inlink->w>>hsub, inlink->h>>vsub,
                      delogo->x>>hsub, delogo->y>>vsub,
                      delogo->w>>hsub, delogo->h>>vsub,
@@ -246,10 +254,10 @@ static int end_frame(AVFilterLink *inlink)
                      delogo->show, direct);
     }
 
-    if ((ret = ff_draw_slice(outlink, 0, inlink->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    if (!direct)
+        avfilter_unref_bufferp(&in);
+
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_delogo_inputs[] = {
@@ -257,9 +265,7 @@ static const AVFilterPad avfilter_vf_delogo_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_inplace_start_frame,
-        .draw_slice       = null_draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
         .min_perms        = AV_PERM_WRITE | AV_PERM_READ,
         .rej_perms        = AV_PERM_PRESERVE
     },
diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c
index fbae0ee..c47422e 100644
--- a/libavfilter/vf_drawbox.c
+++ b/libavfilter/vf_drawbox.c
@@ -96,21 +96,20 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int draw_slice(AVFilterLink *inlink, int y0, int h, int slice_dir)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     DrawBoxContext *drawbox = inlink->dst->priv;
     int plane, x, y, xb = drawbox->x, yb = drawbox->y;
     unsigned char *row[4];
-    AVFilterBufferRef *picref = inlink->cur_buf;
 
-    for (y = FFMAX(yb, y0); y < (y0 + h) && y < (yb + drawbox->h); y++) {
-        row[0] = picref->data[0] + y * picref->linesize[0];
+    for (y = FFMAX(yb, 0); y < frame->video->h && y < (yb + drawbox->h); y++) {
+        row[0] = frame->data[0] + y * frame->linesize[0];
 
         for (plane = 1; plane < 3; plane++)
-            row[plane] = picref->data[plane] +
-                picref->linesize[plane] * (y >> drawbox->vsub);
+            row[plane] = frame->data[plane] +
+                 frame->linesize[plane] * (y >> drawbox->vsub);
 
-        for (x = FFMAX(xb, 0); x < (xb + drawbox->w) && x < picref->video->w; x++) {
+        for (x = FFMAX(xb, 0); x < (xb + drawbox->w) && x < frame->video->w; x++) {
             double alpha = (double)drawbox->yuv_color[A] / 255;
 
             if ((y - yb < 3) || (yb + drawbox->h - y < 4) ||
@@ -122,7 +121,7 @@ static int draw_slice(AVFilterLink *inlink, int y0, int h, int slice_dir)
         }
     }
 
-    return ff_draw_slice(inlink->dst->outputs[0], y0, h, 1);
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_drawbox_inputs[] = {
@@ -131,9 +130,7 @@ static const AVFilterPad avfilter_vf_drawbox_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .draw_slice       = draw_slice,
-        .end_frame        = ff_null_end_frame,
+        .filter_frame     = filter_frame,
         .min_perms        = AV_PERM_WRITE | AV_PERM_READ,
         .rej_perms        = AV_PERM_PRESERVE
     },
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 43a42d8..e1c2bb1 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -792,11 +792,6 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
 static inline int normalize_double(int *n, double d)
 {
     int ret = 0;
@@ -812,20 +807,20 @@ static inline int normalize_double(int *n, double d)
     return ret;
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     DrawTextContext *dtext = ctx->priv;
-    AVFilterBufferRef *buf_out;
     int ret = 0;
 
     if ((ret = dtext_prepare_text(ctx)) < 0) {
         av_log(ctx, AV_LOG_ERROR, "Can't draw text\n");
+        avfilter_unref_bufferp(&frame);
         return ret;
     }
 
-    dtext->var_values[VAR_T] = inpicref->pts == AV_NOPTS_VALUE ?
-        NAN : inpicref->pts * av_q2d(inlink->time_base);
+    dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
+        NAN : frame->pts * av_q2d(inlink->time_base);
     dtext->var_values[VAR_X] =
         av_expr_eval(dtext->x_pexpr, dtext->var_values, &dtext->prng);
     dtext->var_values[VAR_Y] =
@@ -854,29 +849,12 @@ static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
             (int)dtext->var_values[VAR_N], dtext->var_values[VAR_T],
             dtext->x, dtext->y, dtext->x+dtext->w, dtext->y+dtext->h);
 
-    buf_out = avfilter_ref_buffer(inpicref, ~0);
-    if (!buf_out)
-        return AVERROR(ENOMEM);
-
-    return ff_start_frame(inlink->dst->outputs[0], buf_out);
-}
-
-static int end_frame(AVFilterLink *inlink)
-{
-    AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *picref = inlink->cur_buf;
-    DrawTextContext *dtext = inlink->dst->priv;
-    int ret;
-
     if (dtext->draw)
-        draw_text(inlink->dst, picref, picref->video->w, picref->video->h);
+        draw_text(inlink->dst, frame, frame->video->w, frame->video->h);
 
     dtext->var_values[VAR_N] += 1.0;
 
-    if ((ret = ff_draw_slice(outlink, 0, picref->video->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_drawtext_inputs[] = {
@@ -884,9 +862,7 @@ static const AVFilterPad avfilter_vf_drawtext_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = start_frame,
-        .draw_slice       = null_draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
         .config_props     = config_input,
         .min_perms        = AV_PERM_WRITE |
                             AV_PERM_READ,
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index 8555798..f609db1 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -98,17 +98,16 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     FadeContext *fade = inlink->dst->priv;
-    AVFilterBufferRef *outpic = inlink->cur_buf;
     uint8_t *p;
     int i, j, plane;
 
     if (fade->factor < UINT16_MAX) {
         /* luma or rgb plane */
-        for (i = 0; i < h; i++) {
-            p = outpic->data[0] + (y+i) * outpic->linesize[0];
+        for (i = 0; i < frame->video->h; i++) {
+            p = frame->data[0] + i * frame->linesize[0];
             for (j = 0; j < inlink->w * fade->bpp; j++) {
                 /* fade->factor is using 16 lower-order bits for decimal
                  * places. 32768 = 1 << 15, it is an integer representation
@@ -118,11 +117,11 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
             }
         }
 
-        if (outpic->data[1] && outpic->data[2]) {
+        if (frame->data[1] && frame->data[2]) {
             /* chroma planes */
             for (plane = 1; plane < 3; plane++) {
-                for (i = 0; i < h; i++) {
-                    p = outpic->data[plane] + ((y+i) >> fade->vsub) * outpic->linesize[plane];
+                for (i = 0; i < frame->video->h; i++) {
+                    p = frame->data[plane] + (i >> fade->vsub) * frame->linesize[plane];
                     for (j = 0; j < inlink->w >> fade->hsub; j++) {
                         /* 8421367 = ((128 << 1) + 1) << 15. It is an integer
                          * representation of 128.5. The .5 is for rounding
@@ -135,23 +134,13 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
         }
     }
 
-    return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
-}
-
-static int end_frame(AVFilterLink *inlink)
-{
-    FadeContext *fade = inlink->dst->priv;
-    int ret;
-
-    ret = ff_end_frame(inlink->dst->outputs[0]);
-
     if (fade->frame_index >= fade->start_frame &&
         fade->frame_index <= fade->stop_frame)
         fade->factor += fade->fade_per_frame;
     fade->factor = av_clip_uint16(fade->factor);
     fade->frame_index++;
 
-    return ret;
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_fade_inputs[] = {
@@ -160,9 +149,7 @@ static const AVFilterPad avfilter_vf_fade_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_props,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
         .min_perms        = AV_PERM_READ | AV_PERM_WRITE,
         .rej_perms        = AV_PERM_PRESERVE,
     },
diff --git a/libavfilter/vf_fieldorder.c b/libavfilter/vf_fieldorder.c
index 5e084ac..6fbac1c 100644
--- a/libavfilter/vf_fieldorder.c
+++ b/libavfilter/vf_fieldorder.c
@@ -121,90 +121,39 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int
     return ff_get_video_buffer(outlink, perms, w, h);
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
-    AVFilterContext   *ctx        = inlink->dst;
-    AVFilterLink      *outlink    = ctx->outputs[0];
-
-    AVFilterBufferRef *outpicref, *for_next_filter;
-    int ret = 0;
-
-    outpicref = avfilter_ref_buffer(inpicref, ~0);
-    if (!outpicref)
-        return AVERROR(ENOMEM);
-
-    for_next_filter = avfilter_ref_buffer(outpicref, ~0);
-    if (!for_next_filter) {
-        avfilter_unref_bufferp(&outpicref);
-        return AVERROR(ENOMEM);
-    }
-
-    ret = ff_start_frame(outlink, for_next_filter);
-    if (ret < 0) {
-        avfilter_unref_bufferp(&outpicref);
-        return ret;
-    }
-
-    outlink->out_buf = outpicref;
-    return 0;
-}
-
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    AVFilterContext   *ctx        = inlink->dst;
-    FieldOrderContext *fieldorder = ctx->priv;
-    AVFilterLink      *outlink    = ctx->outputs[0];
-
-    AVFilterBufferRef *inpicref   = inlink->cur_buf;
+    AVFilterContext   *ctx     = inlink->dst;
+    FieldOrderContext *s       = ctx->priv;
+    AVFilterLink      *outlink = ctx->outputs[0];
+    int h, plane, line_step, line_size, line;
+    uint8_t *data;
 
-    /** can only currently do slices if this filter is doing nothing
-     *  because this filter is moving picture content, the output
-     *  slice will contain different video lines than the input slice
-     *  and that complexity will be added later */
-    if (  !inpicref->video->interlaced
-        || inpicref->video->top_field_first == fieldorder->dst_tff) {
-        return ff_draw_slice(outlink, y, h, slice_dir);
-    }
-    return 0;
-}
+    if (!frame->video->interlaced ||
+        frame->video->top_field_first == s->dst_tff)
+        return ff_filter_frame(outlink, frame);
 
-static int end_frame(AVFilterLink *inlink)
-{
-    AVFilterContext   *ctx        = inlink->dst;
-    FieldOrderContext *fieldorder = ctx->priv;
-    AVFilterLink      *outlink    = ctx->outputs[0];
-
-    AVFilterBufferRef *inpicref   = inlink->cur_buf;
-    AVFilterBufferRef *outpicref  = outlink->out_buf;
-
-    int               h, plane, line_step, line_size, line;
-    uint8_t           *cpy_src, *cpy_dst;
-
-    if (    inpicref->video->interlaced
-         && inpicref->video->top_field_first != fieldorder->dst_tff) {
         av_dlog(ctx,
                 "picture will move %s one line\n",
-                fieldorder->dst_tff ? "up" : "down");
-        h = inpicref->video->h;
-        for (plane = 0; plane < 4 && inpicref->data[plane]; plane++) {
-            line_step = inpicref->linesize[plane];
-            line_size = fieldorder->line_size[plane];
-            cpy_src = inpicref->data[plane];
-            cpy_dst = outpicref->data[plane];
-            if (fieldorder->dst_tff) {
+                s->dst_tff ? "up" : "down");
+        h = frame->video->h;
+        for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
+            line_step = frame->linesize[plane];
+            line_size = s->line_size[plane];
+            data = frame->data[plane];
+            if (s->dst_tff) {
                 /** Move every line up one line, working from
                  *  the top to the bottom of the frame.
                  *  The original top line is lost.
                  *  The new last line is created as a copy of the
                  *  penultimate line from that field. */
                 for (line = 0; line < h; line++) {
-                    if (1 + line < outpicref->video->h) {
-                        memcpy(cpy_dst, cpy_src + line_step, line_size);
+                    if (1 + line < frame->video->h) {
+                        memcpy(data, data + line_step, line_size);
                     } else {
-                        memcpy(cpy_dst, cpy_src - line_step - line_step, line_size);
+                        memcpy(data, data - line_step - line_step, line_size);
                     }
-                    cpy_src += line_step;
-                    cpy_dst += line_step;
+                    data += line_step;
                 }
             } else {
                 /** Move every line down one line, working from
@@ -212,27 +161,20 @@ static int end_frame(AVFilterLink *inlink)
                  *  The original bottom line is lost.
                  *  The new first line is created as a copy of the
                  *  second line from that field. */
-                cpy_src += (h - 1) * line_step;
-                cpy_dst += (h - 1) * line_step;
+                data += (h - 1) * line_step;
                 for (line = h - 1; line >= 0 ; line--) {
                     if (line > 0) {
-                        memcpy(cpy_dst, cpy_src - line_step, line_size);
+                        memcpy(data, data - line_step, line_size);
                     } else {
-                        memcpy(cpy_dst, cpy_src + line_step + line_step, line_size);
+                        memcpy(data, data + line_step + line_step, line_size);
                     }
-                    cpy_src -= line_step;
-                    cpy_dst -= line_step;
+                    data -= line_step;
                 }
             }
         }
-        outpicref->video->top_field_first = fieldorder->dst_tff;
-        ff_draw_slice(outlink, 0, h, 1);
-    } else {
-        av_dlog(ctx,
-                "not interlaced or field order already correct\n");
-    }
+        frame->video->top_field_first = s->dst_tff;
 
-    return ff_end_frame(outlink);
+    return ff_filter_frame(outlink, frame);
 }
 
 static const AVFilterPad avfilter_vf_fieldorder_inputs[] = {
@@ -240,10 +182,8 @@ static const AVFilterPad avfilter_vf_fieldorder_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input,
-        .start_frame      = start_frame,
         .get_video_buffer = get_video_buffer,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
         .min_perms        = AV_PERM_READ,
         .rej_perms        = AV_PERM_REUSE2 | AV_PERM_PRESERVE,
     },
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index 72d6348..7e4a26e 100644
--- a/libavfilter/vf_format.c
+++ b/libavfilter/vf_format.c
@@ -104,9 +104,6 @@ static const AVFilterPad avfilter_vf_format_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .draw_slice       = ff_null_draw_slice,
-        .end_frame        = ff_null_end_frame,
     },
     { NULL }
 };
@@ -146,9 +143,6 @@ static const AVFilterPad avfilter_vf_noformat_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .draw_slice       = ff_null_draw_slice,
-        .end_frame        = ff_null_end_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index 45b8225..dc20114 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -144,9 +144,7 @@ static int request_frame(AVFilterLink *outlink)
             buf->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base,
                                     outlink->time_base) + s->frames_out;
 
-            if ((ret = ff_start_frame(outlink, buf)) < 0 ||
-                (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
-                (ret = ff_end_frame(outlink)) < 0)
+            if ((ret = ff_filter_frame(outlink, buf)) < 0)
                 return ret;
 
             s->frames_out++;
@@ -171,16 +169,14 @@ static int write_to_fifo(AVFifoBuffer *fifo, AVFilterBufferRef *buf)
     return 0;
 }
 
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 {
     AVFilterContext    *ctx = inlink->dst;
     FPSContext           *s = ctx->priv;
     AVFilterLink   *outlink = ctx->outputs[0];
-    AVFilterBufferRef  *buf = inlink->cur_buf;
     int64_t delta;
     int i, ret;
 
-    inlink->cur_buf = NULL;
     s->frames_in++;
     /* discard frames until we get the first timestamp */
     if (s->pts == AV_NOPTS_VALUE) {
@@ -251,9 +247,7 @@ static int end_frame(AVFilterLink *inlink)
         buf_out->pts = av_rescale_q(s->first_pts, inlink->time_base,
                                     outlink->time_base) + s->frames_out;
 
-        if ((ret = ff_start_frame(outlink, buf_out)) < 0 ||
-            (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
-            (ret = ff_end_frame(outlink)) < 0) {
+        if ((ret = ff_filter_frame(outlink, buf_out)) < 0) {
             avfilter_unref_bufferp(&buf);
             return ret;
         }
@@ -268,23 +262,11 @@ static int end_frame(AVFilterLink *inlink)
     return ret;
 }
 
-static int null_start_frame(AVFilterLink *link, AVFilterBufferRef *buf)
-{
-    return 0;
-}
-
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
 static const AVFilterPad avfilter_vf_fps_inputs[] = {
     {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
-        .start_frame = null_start_frame,
-        .draw_slice  = null_draw_slice,
-        .end_frame   = end_frame,
+        .filter_frame = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index 471e6fc..fd05390 100644
--- a/libavfilter/vf_frei0r.c
+++ b/libavfilter/vf_frei0r.c
@@ -346,35 +346,34 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     Frei0rContext *frei0r = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef  *inpicref =  inlink->cur_buf;
-    AVFilterBufferRef *outpicref = outlink->out_buf;
-    int ret;
-
-    frei0r->update(frei0r->instance, inpicref->pts * av_q2d(inlink->time_base) * 1000,
-                   (const uint32_t *)inpicref->data[0],
-                   (uint32_t *)outpicref->data[0]);
-    if ((ret = ff_draw_slice(outlink, 0, outlink->h, 1)) ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    AVFilterBufferRef *out;
+
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
+        return AVERROR(ENOMEM);
+    }
+    avfilter_copy_buffer_ref_props(out, in);
+
+    frei0r->update(frei0r->instance, in->pts * av_q2d(inlink->time_base) * 1000,
+                   (const uint32_t *)in->data[0],
+                   (uint32_t *)out->data[0]);
+
+    avfilter_unref_bufferp(&in);
+
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_frei0r_inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .draw_slice   = null_draw_slice,
         .config_props = config_input_props,
-        .end_frame    = end_frame,
+        .filter_frame = filter_frame,
         .min_perms    = AV_PERM_READ
     },
     { NULL }
@@ -456,8 +455,6 @@ static int source_request_frame(AVFilterLink *outlink)
 {
     Frei0rContext *frei0r = outlink->src->priv;
     AVFilterBufferRef *picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
-    AVFilterBufferRef *buf_out;
-    int ret;
 
     if (!picref)
         return AVERROR(ENOMEM);
@@ -466,28 +463,10 @@ static int source_request_frame(AVFilterLink *outlink)
     picref->pts = frei0r->pts++;
     picref->pos = -1;
 
-    buf_out = avfilter_ref_buffer(picref, ~0);
-    if (!buf_out) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    ret = ff_start_frame(outlink, buf_out);
-    if (ret < 0)
-        goto fail;
-
     frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}),
                    NULL, (uint32_t *)picref->data[0]);
-    ret = ff_draw_slice(outlink, 0, outlink->h, 1);
-    if (ret < 0)
-        goto fail;
-
-    ret = ff_end_frame(outlink);
-
-fail:
-    avfilter_unref_buffer(picref);
 
-    return ret;
+    return ff_filter_frame(outlink, picref);
 }
 
 static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = {
diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c
index 2ee8b5d..2c9a976 100644
--- a/libavfilter/vf_gradfun.c
+++ b/libavfilter/vf_gradfun.c
@@ -182,20 +182,29 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     GradFunContext *gf = inlink->dst->priv;
-    AVFilterBufferRef *inpic = inlink->cur_buf;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpic = outlink->out_buf;
-    int p, ret;
+    AVFilterBufferRef *out;
+    int p, direct;
+
+    if ((in->perms & AV_PERM_WRITE) && !(in->perms & AV_PERM_PRESERVE)) {
+        direct = 1;
+        out = in;
+    } else {
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        if (!out) {
+            avfilter_unref_bufferp(&in);
+            return AVERROR(ENOMEM);
+        }
+
+        avfilter_copy_buffer_ref_props(out, in);
+        out->video->w = outlink->w;
+        out->video->h = outlink->h;
+    }
 
-    for (p = 0; p < 4 && inpic->data[p]; p++) {
+    for (p = 0; p < 4 && in->data[p]; p++) {
         int w = inlink->w;
         int h = inlink->h;
         int r = gf->radius;
@@ -206,15 +215,15 @@ static int end_frame(AVFilterLink *inlink)
         }
 
         if (FFMIN(w, h) > 2 * r)
-            filter(gf, outpic->data[p], inpic->data[p], w, h, outpic->linesize[p], inpic->linesize[p], r);
-        else if (outpic->data[p] != inpic->data[p])
-            av_image_copy_plane(outpic->data[p], outpic->linesize[p], inpic->data[p], inpic->linesize[p], w, h);
+            filter(gf, out->data[p], in->data[p], w, h, out->linesize[p], in->linesize[p], r);
+        else if (out->data[p] != in->data[p])
+            av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p], w, h);
     }
 
-    if ((ret = ff_draw_slice(outlink, 0, inlink->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    if (!direct)
+        avfilter_unref_bufferp(&in);
+
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_gradfun_inputs[] = {
@@ -222,9 +231,7 @@ static const AVFilterPad avfilter_vf_gradfun_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
-        .start_frame  = ff_inplace_start_frame,
-        .draw_slice   = null_draw_slice,
-        .end_frame    = end_frame,
+        .filter_frame = filter_frame,
         .min_perms    = AV_PERM_READ,
     },
     { NULL }
diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c
index 3ae0fc6..85a1d92 100644
--- a/libavfilter/vf_hflip.c
+++ b/libavfilter/vf_hflip.c
@@ -84,22 +84,30 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
-    FlipContext *flip = inlink->dst->priv;
-    AVFilterBufferRef *inpic  = inlink->cur_buf;
-    AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf;
+    AVFilterContext *ctx  = inlink->dst;
+    FlipContext *flip     = ctx->priv;
+    AVFilterLink *outlink = ctx->outputs[0];
+    AVFilterBufferRef *out;
     uint8_t *inrow, *outrow;
     int i, j, plane, step, hsub, vsub;
 
-    for (plane = 0; plane < 4 && inpic->data[plane]; plane++) {
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
+        return AVERROR(ENOMEM);
+    }
+    avfilter_copy_buffer_ref_props(out, in);
+
+    for (plane = 0; plane < 4 && in->data[plane]; plane++) {
         step = flip->max_step[plane];
         hsub = (plane == 1 || plane == 2) ? flip->hsub : 0;
         vsub = (plane == 1 || plane == 2) ? flip->vsub : 0;
 
-        outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane];
-        inrow  = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane] + ((inlink->w >> hsub) - 1) * step;
-        for (i = 0; i < h>>vsub; i++) {
+        outrow = out->data[plane];
+        inrow  = in ->data[plane] + ((inlink->w >> hsub) - 1) * step;
+        for (i = 0; i < in->video->h >> vsub; i++) {
             switch (step) {
             case 1:
                 for (j = 0; j < (inlink->w >> hsub); j++)
@@ -140,19 +148,20 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
                     memcpy(outrow + j*step, inrow - j*step, step);
             }
 
-            inrow  += inpic ->linesize[plane];
-            outrow += outpic->linesize[plane];
+            inrow  += in ->linesize[plane];
+            outrow += out->linesize[plane];
         }
     }
 
-    return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_hflip_inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .draw_slice   = draw_slice,
+        .filter_frame = filter_frame,
         .config_props = config_props,
         .min_perms    = AV_PERM_READ,
     },
diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c
index 4ed8905..7365b8d 100644
--- a/libavfilter/vf_hqdn3d.c
+++ b/libavfilter/vf_hqdn3d.c
@@ -322,42 +322,49 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     HQDN3DContext *hqdn3d = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *inpic  = inlink ->cur_buf;
-    AVFilterBufferRef *outpic = outlink->out_buf;
-    int ret, c;
+    AVFilterBufferRef *out;
+    int direct, c;
+
+    if ((in->perms & AV_PERM_WRITE) && !(in->perms & AV_PERM_PRESERVE)) {
+        direct = 1;
+        out = in;
+    } else {
+        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        if (!out) {
+            avfilter_unref_bufferp(&in);
+            return AVERROR(ENOMEM);
+        }
+
+        avfilter_copy_buffer_ref_props(out, in);
+        out->video->w = outlink->w;
+        out->video->h = outlink->h;
+    }
 
     for (c = 0; c < 3; c++) {
-        denoise(hqdn3d, inpic->data[c], outpic->data[c],
+        denoise(hqdn3d, in->data[c], out->data[c],
                 hqdn3d->line, &hqdn3d->frame_prev[c],
-                inpic->video->w >> (!!c * hqdn3d->hsub),
-                inpic->video->h >> (!!c * hqdn3d->vsub),
-                inpic->linesize[c], outpic->linesize[c],
+                in->video->w >> (!!c * hqdn3d->hsub),
+                in->video->h >> (!!c * hqdn3d->vsub),
+                in->linesize[c], out->linesize[c],
                 hqdn3d->coefs[c?2:0], hqdn3d->coefs[c?3:1]);
     }
 
-    if ((ret = ff_draw_slice(outlink, 0, inpic->video->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    if (!direct)
+        avfilter_unref_bufferp(&in);
+
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .start_frame  = ff_inplace_start_frame,
-        .draw_slice   = null_draw_slice,
         .config_props = config_input,
-        .end_frame    = end_frame
+        .filter_frame = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c
index 3e802cd..e558a4a 100644
--- a/libavfilter/vf_libopencv.c
+++ b/libavfilter/vf_libopencv.c
@@ -32,6 +32,7 @@
 #include "libavutil/file.h"
 #include "avfilter.h"
 #include "formats.h"
+#include "internal.h"
 #include "video.h"
 
 static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum AVPixelFormat pixfmt)
@@ -68,11 +69,6 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
 typedef struct {
     const char *name;
     int (*init)(AVFilterContext *ctx, const char *args);
@@ -355,33 +351,36 @@ static av_cold void uninit(AVFilterContext *ctx)
     memset(ocv, 0, sizeof(*ocv));
 }
 
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     AVFilterContext *ctx = inlink->dst;
     OCVContext *ocv = ctx->priv;
     AVFilterLink *outlink= inlink->dst->outputs[0];
-    AVFilterBufferRef *inpicref  = inlink ->cur_buf;
-    AVFilterBufferRef *outpicref = outlink->out_buf;
+    AVFilterBufferRef *out;
     IplImage inimg, outimg;
-    int ret;
 
-    fill_iplimage_from_picref(&inimg , inpicref , inlink->format);
-    fill_iplimage_from_picref(&outimg, outpicref, inlink->format);
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
+        return AVERROR(ENOMEM);
+    }
+    avfilter_copy_buffer_ref_props(out, in);
+
+    fill_iplimage_from_picref(&inimg , in , inlink->format);
+    fill_iplimage_from_picref(&outimg, out, inlink->format);
     ocv->end_frame_filter(ctx, &inimg, &outimg);
-    fill_picref_from_iplimage(outpicref, &outimg, inlink->format);
+    fill_picref_from_iplimage(out, &outimg, inlink->format);
 
-    if ((ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    avfilter_unref_bufferp(&in);
+
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_ocv_inputs[] = {
     {
         .name       = "default",
         .type       = AVMEDIA_TYPE_VIDEO,
-        .draw_slice = null_draw_slice,
-        .end_frame  = end_frame,
+        .filter_frame = filter_frame,
         .min_perms  = AV_PERM_READ
     },
     { NULL }
diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c
index c54d6d5..f265795 100644
--- a/libavfilter/vf_lut.c
+++ b/libavfilter/vf_lut.c
@@ -295,22 +295,28 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     AVFilterContext *ctx = inlink->dst;
     LutContext *lut = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *inpic  = inlink ->cur_buf;
-    AVFilterBufferRef *outpic = outlink->out_buf;
+    AVFilterBufferRef *out;
     uint8_t *inrow, *outrow, *inrow0, *outrow0;
     int i, j, k, plane;
 
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
+        return AVERROR(ENOMEM);
+    }
+    avfilter_copy_buffer_ref_props(out, in);
+
     if (lut->is_rgb) {
         /* packed */
-        inrow0  = inpic ->data[0] + y * inpic ->linesize[0];
-        outrow0 = outpic->data[0] + y * outpic->linesize[0];
+        inrow0  = in ->data[0];
+        outrow0 = out->data[0];
 
-        for (i = 0; i < h; i ++) {
+        for (i = 0; i < in->video->h; i ++) {
             inrow  = inrow0;
             outrow = outrow0;
             for (j = 0; j < inlink->w; j++) {
@@ -319,34 +325,35 @@ static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
                 outrow += lut->step;
                 inrow  += lut->step;
             }
-            inrow0  += inpic ->linesize[0];
-            outrow0 += outpic->linesize[0];
+            inrow0  += in ->linesize[0];
+            outrow0 += out->linesize[0];
         }
     } else {
         /* planar */
-        for (plane = 0; plane < 4 && inpic->data[plane]; plane++) {
+        for (plane = 0; plane < 4 && in->data[plane]; plane++) {
             int vsub = plane == 1 || plane == 2 ? lut->vsub : 0;
             int hsub = plane == 1 || plane == 2 ? lut->hsub : 0;
 
-            inrow  = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane];
-            outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane];
+            inrow  = in ->data[plane];
+            outrow = out->data[plane];
 
-            for (i = 0; i < h>>vsub; i ++) {
+            for (i = 0; i < in->video->h >> vsub; i ++) {
                 for (j = 0; j < inlink->w>>hsub; j++)
                     outrow[j] = lut->lut[plane][inrow[j]];
-                inrow  += inpic ->linesize[plane];
-                outrow += outpic->linesize[plane];
+                inrow  += in ->linesize[plane];
+                outrow += out->linesize[plane];
             }
         }
     }
 
-    return ff_draw_slice(outlink, y, h, slice_dir);
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad inputs[] = {
     { .name            = "default",
       .type            = AVMEDIA_TYPE_VIDEO,
-      .draw_slice      = draw_slice,
+      .filter_frame    = filter_frame,
       .config_props    = config_props,
       .min_perms       = AV_PERM_READ, },
     { .name = NULL}
diff --git a/libavfilter/vf_null.c b/libavfilter/vf_null.c
index 87e4820..a7abb7a 100644
--- a/libavfilter/vf_null.c
+++ b/libavfilter/vf_null.c
@@ -31,8 +31,6 @@ static const AVFilterPad avfilter_vf_null_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .end_frame        = ff_null_end_frame
     },
     { NULL }
 };
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index 8fb44e3..8741d48 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -269,34 +269,22 @@ static void blend_frame(AVFilterContext *ctx,
     }
 }
 
-static int null_start_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
-{
-    return 0;
-}
-
-static int null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
-static int end_frame_main(AVFilterLink *inlink)
+static int filter_frame_main(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     OverlayContext *s = inlink->dst->priv;
 
     av_assert0(!s->main);
-    s->main         = inlink->cur_buf;
-    inlink->cur_buf = NULL;
+    s->main         = frame;
 
     return 0;
 }
 
-static int end_frame_overlay(AVFilterLink *inlink)
+static int filter_frame_overlay(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     OverlayContext *s = inlink->dst->priv;
 
     av_assert0(!s->over_next);
-    s->over_next    = inlink->cur_buf;
-    inlink->cur_buf = NULL;
+    s->over_next    = frame;
 
     return 0;
 }
@@ -305,11 +293,7 @@ static int output_frame(AVFilterContext *ctx)
 {
     OverlayContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    int ret = ff_start_frame(outlink, s->main);
-    if (ret >= 0)
-        ret = ff_draw_slice(outlink, 0, outlink->h, 1);
-    if (ret >= 0)
-        ret = ff_end_frame(outlink);
+    int ret = ff_filter_frame(outlink, s->main);
     s->main = NULL;
 
     return ret;
@@ -378,10 +362,8 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = {
     {
         .name         = "main",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .start_frame  = null_start_frame,
         .config_props = config_input_main,
-        .draw_slice   = null_draw_slice,
-        .end_frame    = end_frame_main,
+        .filter_frame = filter_frame_main,
         .min_perms    = AV_PERM_READ,
         .rej_perms    = AV_PERM_REUSE2 | AV_PERM_PRESERVE,
         .needs_fifo   = 1,
@@ -389,10 +371,8 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = {
     {
         .name         = "overlay",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .start_frame  = null_start_frame,
         .config_props = config_input_overlay,
-        .draw_slice   = null_draw_slice,
-        .end_frame    = end_frame_overlay,
+        .filter_frame = filter_frame_overlay,
         .min_perms    = AV_PERM_READ,
         .rej_perms    = AV_PERM_REUSE2,
         .needs_fifo   = 1,
diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c
index c14835d..f1a890e 100644
--- a/libavfilter/vf_pad.c
+++ b/libavfilter/vf_pad.c
@@ -106,7 +106,6 @@ typedef struct {
     uint8_t *line[4];
     int      line_step[4];
     int hsub, vsub;         ///< chroma subsampling values
-    int needs_copy;
 } PadContext;
 
 static av_cold int init(AVFilterContext *ctx, const char *args)
@@ -303,135 +302,85 @@ static int does_clip(PadContext *pad, AVFilterBufferRef *outpicref, int plane, i
     return 0;
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     PadContext *pad = inlink->dst->priv;
-    AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
-    AVFilterBufferRef *for_next_filter;
-    int plane, ret = 0;
+    AVFilterBufferRef *out = avfilter_ref_buffer(in, ~0);
+    int plane, needs_copy;
 
-    if (!outpicref)
+    if (!out) {
+        avfilter_unref_bufferp(&in);
         return AVERROR(ENOMEM);
+    }
 
-    for (plane = 0; plane < 4 && outpicref->data[plane]; plane++) {
+    for (plane = 0; plane < 4 && out->data[plane]; plane++) {
         int hsub = (plane == 1 || plane == 2) ? pad->hsub : 0;
         int vsub = (plane == 1 || plane == 2) ? pad->vsub : 0;
 
-        av_assert0(outpicref->buf->w>0 && outpicref->buf->h>0);
+        av_assert0(out->buf->w > 0 && out->buf->h > 0);
 
-        if(outpicref->format != outpicref->buf->format) //unsupported currently
+        if (out->format != out->buf->format) //unsupported currently
             break;
 
-        outpicref->data[plane] -=   (pad->x  >> hsub) * pad      ->line_step[plane]
-                                  + (pad->y  >> vsub) * outpicref->linesize [plane];
+        out->data[plane] -= (pad->x  >> hsub) * pad->line_step[plane] +
+                            (pad->y  >> vsub) * out->linesize [plane];
 
-        if(   does_clip(pad, outpicref, plane, hsub, vsub, 0, 0)
-           || does_clip(pad, outpicref, plane, hsub, vsub, 0, pad->h-1)
-           || does_clip(pad, outpicref, plane, hsub, vsub, pad->w-1, 0)
-           || does_clip(pad, outpicref, plane, hsub, vsub, pad->w-1, pad->h-1)
-          )
+        if (does_clip(pad, out, plane, hsub, vsub, 0,                   0) ||
+            does_clip(pad, out, plane, hsub, vsub, 0,          pad->h - 1) ||
+            does_clip(pad, out, plane, hsub, vsub, pad->w - 1,          0) ||
+            does_clip(pad, out, plane, hsub, vsub, pad->w - 1, pad->h - 1))
             break;
     }
-    pad->needs_copy= plane < 4 && outpicref->data[plane];
-    if(pad->needs_copy){
+    needs_copy = plane < 4 && out->data[plane];
+    if (needs_copy) {
         av_log(inlink->dst, AV_LOG_DEBUG, "Direct padding impossible allocating new frame\n");
-        avfilter_unref_buffer(outpicref);
-        outpicref = ff_get_video_buffer(inlink->dst->outputs[0], AV_PERM_WRITE | AV_PERM_NEG_LINESIZES,
-                                        FFMAX(inlink->w, pad->w),
-                                        FFMAX(inlink->h, pad->h));
-        if (!outpicref)
+        avfilter_unref_buffer(out);
+        out = ff_get_video_buffer(inlink->dst->outputs[0], AV_PERM_WRITE | AV_PERM_NEG_LINESIZES,
+                                  FFMAX(inlink->w, pad->w),
+                                  FFMAX(inlink->h, pad->h));
+        if (!out) {
+            avfilter_unref_bufferp(&in);
             return AVERROR(ENOMEM);
+        }
 
-        avfilter_copy_buffer_ref_props(outpicref, inpicref);
-    }
-
-    outpicref->video->w = pad->w;
-    outpicref->video->h = pad->h;
-
-    for_next_filter = avfilter_ref_buffer(outpicref, ~0);
-    if (!for_next_filter) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
+        avfilter_copy_buffer_ref_props(out, in);
     }
 
-    ret = ff_start_frame(inlink->dst->outputs[0], for_next_filter);
-    if (ret < 0)
-        goto fail;
-
-    inlink->dst->outputs[0]->out_buf = outpicref;
-    return 0;
-
-fail:
-    avfilter_unref_bufferp(&outpicref);
-    return ret;
-}
-
-static int end_frame(AVFilterLink *link)
-{
-    return ff_end_frame(link->dst->outputs[0]);
-}
+    out->video->w = pad->w;
+    out->video->h = pad->h;
 
-static int draw_send_bar_slice(AVFilterLink *link, int y, int h, int slice_dir, int before_slice)
-{
-    PadContext *pad = link->dst->priv;
-    int bar_y, bar_h = 0, ret = 0;
-
-    if        (slice_dir * before_slice ==  1 && y == pad->y) {
-        /* top bar */
-        bar_y = 0;
-        bar_h = pad->y;
-    } else if (slice_dir * before_slice == -1 && (y + h) == (pad->y + pad->in_h)) {
-        /* bottom bar */
-        bar_y = pad->y + pad->in_h;
-        bar_h = pad->h - pad->in_h - pad->y;
+    /* top bar */
+    if (pad->y) {
+        ff_draw_rectangle(out->data, out->linesize,
+                          pad->line, pad->line_step, pad->hsub, pad->vsub,
+                          0, 0, pad->w, pad->y);
     }
 
-    if (bar_h) {
-        ff_draw_rectangle(link->dst->outputs[0]->out_buf->data,
-                          link->dst->outputs[0]->out_buf->linesize,
+    /* bottom bar */
+    if (pad->h > pad->y + pad->in_h) {
+        ff_draw_rectangle(out->data, out->linesize,
                           pad->line, pad->line_step, pad->hsub, pad->vsub,
-                          0, bar_y, pad->w, bar_h);
-        ret = ff_draw_slice(link->dst->outputs[0], bar_y, bar_h, slice_dir);
+                          0, pad->y + pad->in_h, pad->w, pad->h - pad->y - pad->in_h);
     }
-    return ret;
-}
-
-static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    PadContext *pad = link->dst->priv;
-    AVFilterBufferRef *outpic = link->dst->outputs[0]->out_buf;
-    AVFilterBufferRef *inpic = link->cur_buf;
-    int ret;
-
-    y += pad->y;
-
-    y &= ~((1 << pad->vsub) - 1);
-    h &= ~((1 << pad->vsub) - 1);
-
-    if (!h)
-        return 0;
-    draw_send_bar_slice(link, y, h, slice_dir, 1);
 
     /* left border */
-    ff_draw_rectangle(outpic->data, outpic->linesize, pad->line, pad->line_step,
-                      pad->hsub, pad->vsub, 0, y, pad->x, h);
-
-    if(pad->needs_copy){
-        ff_copy_rectangle(outpic->data, outpic->linesize,
-                          inpic->data, inpic->linesize, pad->line_step,
-                          pad->hsub, pad->vsub,
-                          pad->x, y, y-pad->y, inpic->video->w, h);
+    ff_draw_rectangle(out->data, out->linesize, pad->line, pad->line_step,
+                      pad->hsub, pad->vsub, 0, pad->y, pad->x, in->video->h);
+
+    if (needs_copy) {
+        ff_copy_rectangle(out->data, out->linesize, in->data, in->linesize,
+                          pad->line_step, pad->hsub, pad->vsub,
+                          pad->x, pad->y, 0, in->video->w, in->video->h);
     }
 
     /* right border */
-    ff_draw_rectangle(outpic->data, outpic->linesize,
+    ff_draw_rectangle(out->data, out->linesize,
                       pad->line, pad->line_step, pad->hsub, pad->vsub,
-                      pad->x + pad->in_w, y, pad->w - pad->x - pad->in_w, h);
-    ret = ff_draw_slice(link->dst->outputs[0], y, h, slice_dir);
-    if (ret < 0)
-        return ret;
+                      pad->x + pad->in_w, pad->y, pad->w - pad->x - pad->in_w,
+                      in->video->h);
 
-    return draw_send_bar_slice(link, y, h, slice_dir, -1);
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(inlink->dst->outputs[0], out);
 }
 
 static const AVFilterPad avfilter_vf_pad_inputs[] = {
@@ -440,9 +389,7 @@ static const AVFilterPad avfilter_vf_pad_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input,
         .get_video_buffer = get_video_buffer,
-        .start_frame      = start_frame,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index 09decea..a1e982c 100644
--- a/libavfilter/vf_pixdesctest.c
+++ b/libavfilter/vf_pixdesctest.c
@@ -52,86 +52,65 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     PixdescTestContext *priv = inlink->dst->priv;
     AVFilterLink *outlink    = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpicref, *for_next_filter;
-    int i, ret = 0;
+    AVFilterBufferRef *out;
+    int i, c, w = inlink->w, h = inlink->h;
 
-    outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE,
-                                    outlink->w, outlink->h);
-    if (!outpicref)
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE,
+                              outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
         return AVERROR(ENOMEM);
+    }
 
-    avfilter_copy_buffer_ref_props(outpicref, picref);
+    avfilter_copy_buffer_ref_props(out, in);
 
     for (i = 0; i < 4; i++) {
         int h = outlink->h;
         h = i == 1 || i == 2 ? h>>priv->pix_desc->log2_chroma_h : h;
-        if (outpicref->data[i]) {
-            uint8_t *data = outpicref->data[i] +
-                (outpicref->linesize[i] > 0 ? 0 : outpicref->linesize[i] * (h-1));
-            memset(data, 0, FFABS(outpicref->linesize[i]) * h);
+        if (out->data[i]) {
+            uint8_t *data = out->data[i] +
+                (out->linesize[i] > 0 ? 0 : out->linesize[i] * (h-1));
+            memset(data, 0, FFABS(out->linesize[i]) * h);
         }
     }
 
     /* copy palette */
     if (priv->pix_desc->flags & PIX_FMT_PAL ||
         priv->pix_desc->flags & PIX_FMT_PSEUDOPAL)
-        memcpy(outpicref->data[1], outpicref->data[1], 256*4);
-
-    for_next_filter = avfilter_ref_buffer(outpicref, ~0);
-    if (for_next_filter)
-        ret = ff_start_frame(outlink, for_next_filter);
-    else
-        ret = AVERROR(ENOMEM);
-
-    if (ret < 0) {
-        avfilter_unref_bufferp(&outpicref);
-        return ret;
-    }
-
-    outlink->out_buf = outpicref;
-    return 0;
-}
-
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    PixdescTestContext *priv = inlink->dst->priv;
-    AVFilterBufferRef *inpic    = inlink->cur_buf;
-    AVFilterBufferRef *outpic   = inlink->dst->outputs[0]->out_buf;
-    int i, c, w = inlink->w;
+        memcpy(out->data[1], in->data[1], 256*4);
 
     for (c = 0; c < priv->pix_desc->nb_components; c++) {
         int w1 = c == 1 || c == 2 ? w>>priv->pix_desc->log2_chroma_w : w;
         int h1 = c == 1 || c == 2 ? h>>priv->pix_desc->log2_chroma_h : h;
-        int y1 = c == 1 || c == 2 ? y>>priv->pix_desc->log2_chroma_h : y;
 
-        for (i = y1; i < y1 + h1; i++) {
+        for (i = 0; i < h1; i++) {
             av_read_image_line(priv->line,
-                               inpic->data,
-                               inpic->linesize,
+                               in->data,
+                               in->linesize,
                                priv->pix_desc,
                                0, i, c, w1, 0);
 
             av_write_image_line(priv->line,
-                                outpic->data,
-                                outpic->linesize,
+                                out->data,
+                                out->linesize,
                                 priv->pix_desc,
                                 0, i, c, w1);
         }
     }
 
-    return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_pixdesctest_inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .start_frame  = start_frame,
-        .draw_slice   = draw_slice,
+        .filter_frame = filter_frame,
         .config_props = config_props,
         .min_perms    = AV_PERM_READ,
     },
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index cbc1081..7f189a2 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -257,93 +257,46 @@ fail:
     return ret;
 }
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
 {
     ScaleContext *scale = link->dst->priv;
     AVFilterLink *outlink = link->dst->outputs[0];
-    AVFilterBufferRef *outpicref, *for_next_filter;
+    AVFilterBufferRef *out;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
-    int ret = 0;
 
-    if (!scale->sws) {
-        outpicref = avfilter_ref_buffer(picref, ~0);
-        if (!outpicref)
-            return AVERROR(ENOMEM);
-        return ff_start_frame(outlink, outpicref);
-    }
+    if (!scale->sws)
+        return ff_filter_frame(outlink, in);
 
     scale->hsub = desc->log2_chroma_w;
     scale->vsub = desc->log2_chroma_h;
 
-    outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
-    if (!outpicref)
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
         return AVERROR(ENOMEM);
-
-    avfilter_copy_buffer_ref_props(outpicref, picref);
-    outpicref->video->w = outlink->w;
-    outpicref->video->h = outlink->h;
-
-
-    av_reduce(&outpicref->video->pixel_aspect.num, &outpicref->video->pixel_aspect.den,
-              (int64_t)picref->video->pixel_aspect.num * outlink->h * link->w,
-              (int64_t)picref->video->pixel_aspect.den * outlink->w * link->h,
-              INT_MAX);
-
-    scale->slice_y = 0;
-    for_next_filter = avfilter_ref_buffer(outpicref, ~0);
-    if (for_next_filter)
-        ret = ff_start_frame(outlink, for_next_filter);
-    else
-        ret = AVERROR(ENOMEM);
-
-    if (ret < 0) {
-        avfilter_unref_bufferp(&outpicref);
-        return ret;
     }
 
-    outlink->out_buf = outpicref;
-    return 0;
-}
+    avfilter_copy_buffer_ref_props(out, in);
+    out->video->w = outlink->w;
+    out->video->h = outlink->h;
 
-static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    ScaleContext *scale = link->dst->priv;
-    int out_h, ret;
-    AVFilterBufferRef *cur_pic = link->cur_buf;
-    const uint8_t *data[4];
+    av_reduce(&out->video->pixel_aspect.num, &out->video->pixel_aspect.den,
+              (int64_t)in->video->pixel_aspect.num * outlink->h * link->w,
+              (int64_t)in->video->pixel_aspect.den * outlink->w * link->h,
+              INT_MAX);
 
-    if (!scale->sws) {
-        return ff_draw_slice(link->dst->outputs[0], y, h, slice_dir);
-    }
+    sws_scale(scale->sws, in->data, in->linesize, 0, in->video->h,
+              out->data, out->linesize);
 
-    if (scale->slice_y == 0 && slice_dir == -1)
-        scale->slice_y = link->dst->outputs[0]->h;
-
-    data[0] = cur_pic->data[0] +  y               * cur_pic->linesize[0];
-    data[1] = scale->input_is_pal ?
-              cur_pic->data[1] :
-              cur_pic->data[1] + (y>>scale->vsub) * cur_pic->linesize[1];
-    data[2] = cur_pic->data[2] + (y>>scale->vsub) * cur_pic->linesize[2];
-    data[3] = cur_pic->data[3] +  y               * cur_pic->linesize[3];
-
-    out_h = sws_scale(scale->sws, data, cur_pic->linesize, y, h,
-                      link->dst->outputs[0]->out_buf->data,
-                      link->dst->outputs[0]->out_buf->linesize);
-
-    if (slice_dir == -1)
-        scale->slice_y -= out_h;
-    ret = ff_draw_slice(link->dst->outputs[0], scale->slice_y, out_h, slice_dir);
-    if (slice_dir == 1)
-        scale->slice_y += out_h;
-    return ret;
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_scale_inputs[] = {
     {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
-        .start_frame = start_frame,
-        .draw_slice  = draw_slice,
+        .filter_frame = filter_frame,
         .min_perms   = AV_PERM_READ,
     },
     { NULL }
diff --git a/libavfilter/vf_select.c b/libavfilter/vf_select.c
index 25c6a14..674151d 100644
--- a/libavfilter/vf_select.c
+++ b/libavfilter/vf_select.c
@@ -228,50 +228,27 @@ static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *picref)
     return res;
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     SelectContext *select = inlink->dst->priv;
 
-    select->select = select_frame(inlink->dst, picref);
+    select->select = select_frame(inlink->dst, frame);
     if (select->select) {
-        AVFilterBufferRef *buf_out;
         /* frame was requested through poll_frame */
         if (select->cache_frames) {
-            if (!av_fifo_space(select->pending_frames))
+            if (!av_fifo_space(select->pending_frames)) {
                 av_log(inlink->dst, AV_LOG_ERROR,
                        "Buffering limit reached, cannot cache more frames\n");
-            else
-                av_fifo_generic_write(select->pending_frames, &picref,
-                                      sizeof(picref), NULL);
+                avfilter_unref_bufferp(&frame);
+            } else
+                av_fifo_generic_write(select->pending_frames, &frame,
+                                      sizeof(frame), NULL);
             return 0;
         }
-        buf_out = avfilter_ref_buffer(picref, ~0);
-        if (!buf_out)
-            return AVERROR(ENOMEM);
-        return ff_start_frame(inlink->dst->outputs[0], buf_out);
+        return ff_filter_frame(inlink->dst->outputs[0], frame);
     }
 
-    return 0;
-}
-
-static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    SelectContext *select = inlink->dst->priv;
-
-    if (select->select && !select->cache_frames)
-        return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
-    return 0;
-}
-
-static int end_frame(AVFilterLink *inlink)
-{
-    SelectContext *select = inlink->dst->priv;
-
-    if (select->select) {
-        if (select->cache_frames)
-            return 0;
-        return ff_end_frame(inlink->dst->outputs[0]);
-    }
+    avfilter_unref_bufferp(&frame);
     return 0;
 }
 
@@ -284,14 +261,9 @@ static int request_frame(AVFilterLink *outlink)
 
     if (av_fifo_size(select->pending_frames)) {
         AVFilterBufferRef *picref;
-        int ret;
 
         av_fifo_generic_read(select->pending_frames, &picref, sizeof(picref), NULL);
-        if ((ret = ff_start_frame(outlink, picref)) < 0 ||
-            (ret = ff_draw_slice(outlink, 0, outlink->h, 1)) < 0 ||
-            (ret = ff_end_frame(outlink)) < 0);
-
-        return ret;
+        return ff_filter_frame(outlink, picref);
     }
 
     while (!select->select) {
@@ -346,9 +318,7 @@ static const AVFilterPad avfilter_vf_select_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
         .config_props     = config_input,
-        .start_frame      = start_frame,
-        .draw_slice       = draw_slice,
-        .end_frame        = end_frame
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_setpts.c b/libavfilter/vf_setpts.c
index f2b86a1..0c4881e 100644
--- a/libavfilter/vf_setpts.c
+++ b/libavfilter/vf_setpts.c
@@ -102,39 +102,36 @@ static int config_input(AVFilterLink *inlink)
 #define D2TS(d)  (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     SetPTSContext *setpts = inlink->dst->priv;
+    int64_t in_pts = frame->pts;
     double d;
-    AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
-
-    if (!outpicref)
-        return AVERROR(ENOMEM);
 
     if (isnan(setpts->var_values[VAR_STARTPTS]))
-        setpts->var_values[VAR_STARTPTS] = TS2D(inpicref->pts);
+        setpts->var_values[VAR_STARTPTS] = TS2D(frame->pts);
 
-    setpts->var_values[VAR_INTERLACED] = inpicref->video->interlaced;
-    setpts->var_values[VAR_PTS       ] = TS2D(inpicref->pts);
-    setpts->var_values[VAR_POS       ] = inpicref->pos == -1 ? NAN : inpicref->pos;
+    setpts->var_values[VAR_INTERLACED] = frame->video->interlaced;
+    setpts->var_values[VAR_PTS       ] = TS2D(frame->pts);
+    setpts->var_values[VAR_POS       ] = frame->pos == -1 ? NAN : frame->pos;
 
     d = av_expr_eval(setpts->expr, setpts->var_values, NULL);
-    outpicref->pts = D2TS(d);
+    frame->pts = D2TS(d);
 
 #ifdef DEBUG
     av_log(inlink->dst, AV_LOG_DEBUG,
            "n:%"PRId64" interlaced:%d pos:%"PRId64" pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n",
            (int64_t)setpts->var_values[VAR_N],
            (int)setpts->var_values[VAR_INTERLACED],
-           inpicref ->pos,
-           inpicref ->pts, inpicref ->pts * av_q2d(inlink->time_base),
-           outpicref->pts, outpicref->pts * av_q2d(inlink->time_base));
+           frame->pos, in_pts, in_pts * av_q2d(inlink->time_base),
+           frame->pts, frame->pts * av_q2d(inlink->time_base));
 #endif
 
+
     setpts->var_values[VAR_N] += 1.0;
-    setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts);
-    setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts);
-    return ff_start_frame(inlink->dst->outputs[0], outpicref);
+    setpts->var_values[VAR_PREV_INPTS ] = TS2D(in_pts);
+    setpts->var_values[VAR_PREV_OUTPTS] = TS2D(frame->pts);
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static av_cold void uninit(AVFilterContext *ctx)
@@ -150,7 +147,7 @@ static const AVFilterPad avfilter_vf_setpts_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
         .config_props     = config_input,
-        .start_frame      = start_frame,
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_settb.c b/libavfilter/vf_settb.c
index 0b68b34..a572072 100644
--- a/libavfilter/vf_settb.c
+++ b/libavfilter/vf_settb.c
@@ -108,21 +108,20 @@ static int config_output_props(AVFilterLink *outlink)
     return 0;
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
 
     if (av_cmp_q(inlink->time_base, outlink->time_base)) {
-        int64_t orig_pts = picref->pts;
-        picref->pts = av_rescale_q(picref->pts, inlink->time_base, outlink->time_base);
+        int64_t orig_pts = frame->pts;
+        frame->pts = av_rescale_q(frame->pts, inlink->time_base, outlink->time_base);
         av_log(ctx, AV_LOG_DEBUG, "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
                inlink ->time_base.num, inlink ->time_base.den, orig_pts,
-               outlink->time_base.num, outlink->time_base.den, picref->pts);
+               outlink->time_base.num, outlink->time_base.den, frame->pts);
     }
-    inlink->cur_buf = NULL;
 
-    return ff_start_frame(outlink, picref);
+    return ff_filter_frame(outlink, frame);
 }
 
 static const AVFilterPad avfilter_vf_settb_inputs[] = {
@@ -130,8 +129,7 @@ static const AVFilterPad avfilter_vf_settb_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = start_frame,
-        .end_frame        = ff_null_end_frame
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index 4b78276..c89b028 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -41,24 +41,23 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int end_frame(AVFilterLink *inlink)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     ShowInfoContext *showinfo = ctx->priv;
-    AVFilterBufferRef *picref = inlink->cur_buf;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     uint32_t plane_checksum[4] = {0}, checksum = 0;
     int i, plane, vsub = desc->log2_chroma_h;
 
-    for (plane = 0; picref->data[plane] && plane < 4; plane++) {
-        size_t linesize = av_image_get_linesize(picref->format, picref->video->w, plane);
-        uint8_t *data = picref->data[plane];
+    for (plane = 0; frame->data[plane] && plane < 4; plane++) {
+        size_t linesize = av_image_get_linesize(frame->format, frame->video->w, plane);
+        uint8_t *data = frame->data[plane];
         int h = plane == 1 || plane == 2 ? inlink->h >> vsub : inlink->h;
 
         for (i = 0; i < h; i++) {
             plane_checksum[plane] = av_adler32_update(plane_checksum[plane], data, linesize);
             checksum = av_adler32_update(checksum, data, linesize);
-            data += picref->linesize[plane];
+            data += frame->linesize[plane];
         }
     }
 
@@ -67,18 +66,18 @@ static int end_frame(AVFilterLink *inlink)
            "fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c "
            "checksum:%u plane_checksum:[%u %u %u %u]\n",
            showinfo->frame,
-           picref->pts, picref->pts * av_q2d(inlink->time_base), picref->pos,
+           frame->pts, frame->pts * av_q2d(inlink->time_base), frame->pos,
            desc->name,
-           picref->video->pixel_aspect.num, picref->video->pixel_aspect.den,
-           picref->video->w, picref->video->h,
-           !picref->video->interlaced     ? 'P' :         /* Progressive  */
-           picref->video->top_field_first ? 'T' : 'B',    /* Top / Bottom */
-           picref->video->key_frame,
-           av_get_picture_type_char(picref->video->pict_type),
+           frame->video->pixel_aspect.num, frame->video->pixel_aspect.den,
+           frame->video->w, frame->video->h,
+           !frame->video->interlaced     ? 'P' :         /* Progressive  */
+           frame->video->top_field_first ? 'T' : 'B',    /* Top / Bottom */
+           frame->video->key_frame,
+           av_get_picture_type_char(frame->video->pict_type),
            checksum, plane_checksum[0], plane_checksum[1], plane_checksum[2], plane_checksum[3]);
 
     showinfo->frame++;
-    return ff_end_frame(inlink->dst->outputs[0]);
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad avfilter_vf_showinfo_inputs[] = {
@@ -86,8 +85,7 @@ static const AVFilterPad avfilter_vf_showinfo_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .start_frame      = ff_null_start_frame,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
         .min_perms        = AV_PERM_READ,
     },
     { NULL }
diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c
index 1ee645f..d7a1739 100644
--- a/libavfilter/vf_transpose.c
+++ b/libavfilter/vf_transpose.c
@@ -121,100 +121,88 @@ static int config_props_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 {
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *buf_out;
+    TransContext *trans = inlink->dst->priv;
+    AVFilterBufferRef *out;
+    int plane;
 
-    outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE,
-                                           outlink->w, outlink->h);
-    if (!outlink->out_buf)
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
         return AVERROR(ENOMEM);
+    }
 
-    outlink->out_buf->pts = picref->pts;
+    out->pts = in->pts;
 
-    if (picref->video->pixel_aspect.num == 0) {
-        outlink->out_buf->video->pixel_aspect = picref->video->pixel_aspect;
+    if (in->video->pixel_aspect.num == 0) {
+        out->video->pixel_aspect = in->video->pixel_aspect;
     } else {
-        outlink->out_buf->video->pixel_aspect.num = picref->video->pixel_aspect.den;
-        outlink->out_buf->video->pixel_aspect.den = picref->video->pixel_aspect.num;
+        out->video->pixel_aspect.num = in->video->pixel_aspect.den;
+        out->video->pixel_aspect.den = in->video->pixel_aspect.num;
     }
 
-    buf_out = avfilter_ref_buffer(outlink->out_buf, ~0);
-    if (!buf_out)
-        return AVERROR(ENOMEM);
-    return ff_start_frame(outlink, buf_out);
-}
-
-static int end_frame(AVFilterLink *inlink)
-{
-    TransContext *trans = inlink->dst->priv;
-    AVFilterBufferRef *inpic  = inlink->cur_buf;
-    AVFilterBufferRef *outpic = inlink->dst->outputs[0]->out_buf;
-    AVFilterLink *outlink = inlink->dst->outputs[0];
-    int plane, ret;
-
-    for (plane = 0; outpic->data[plane]; plane++) {
+    for (plane = 0; out->data[plane]; plane++) {
         int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
         int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
         int pixstep = trans->pixsteps[plane];
-        int inh  = inpic->video->h>>vsub;
-        int outw = outpic->video->w>>hsub;
-        int outh = outpic->video->h>>vsub;
-        uint8_t *out, *in;
-        int outlinesize, inlinesize;
+        int inh  = in->video->h>>vsub;
+        int outw = out->video->w>>hsub;
+        int outh = out->video->h>>vsub;
+        uint8_t *dst, *src;
+        int dstlinesize, srclinesize;
         int x, y;
 
-        out = outpic->data[plane]; outlinesize = outpic->linesize[plane];
-        in  = inpic ->data[plane]; inlinesize  = inpic ->linesize[plane];
+        dst = out->data[plane];
+        dstlinesize = out->linesize[plane];
+        src = in->data[plane];
+        srclinesize = in->linesize[plane];
 
         if (trans->dir&1) {
-            in +=  inpic->linesize[plane] * (inh-1);
-            inlinesize *= -1;
+            src +=  in->linesize[plane] * (inh-1);
+            srclinesize *= -1;
         }
 
         if (trans->dir&2) {
-            out += outpic->linesize[plane] * (outh-1);
-            outlinesize *= -1;
+            dst += out->linesize[plane] * (outh-1);
+            dstlinesize *= -1;
         }
 
         for (y = 0; y < outh; y++) {
             switch (pixstep) {
             case 1:
                 for (x = 0; x < outw; x++)
-                    out[x] = in[x*inlinesize + y];
+                    dst[x] = src[x*srclinesize + y];
                 break;
             case 2:
                 for (x = 0; x < outw; x++)
-                    *((uint16_t *)(out + 2*x)) = *((uint16_t *)(in + x*inlinesize + y*2));
+                    *((uint16_t *)(dst + 2*x)) = *((uint16_t *)(src + x*srclinesize + y*2));
                 break;
             case 3:
                 for (x = 0; x < outw; x++) {
-                    int32_t v = AV_RB24(in + x*inlinesize + y*3);
-                    AV_WB24(out + 3*x, v);
+                    int32_t v = AV_RB24(src + x*srclinesize + y*3);
+                    AV_WB24(dst + 3*x, v);
                 }
                 break;
             case 4:
                 for (x = 0; x < outw; x++)
-                    *((uint32_t *)(out + 4*x)) = *((uint32_t *)(in + x*inlinesize + y*4));
+                    *((uint32_t *)(dst + 4*x)) = *((uint32_t *)(src + x*srclinesize + y*4));
                 break;
             }
-            out += outlinesize;
+            dst += dstlinesize;
         }
     }
 
-    if ((ret = ff_draw_slice(outlink, 0, outpic->video->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-    return 0;
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_transpose_inputs[] = {
     {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
-        .start_frame = start_frame,
-        .end_frame   = end_frame,
+        .filter_frame = filter_frame,
         .min_perms   = AV_PERM_READ,
     },
     { NULL }
diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c
index 7e50bb8..b446937 100644
--- a/libavfilter/vf_unsharp.c
+++ b/libavfilter/vf_unsharp.c
@@ -214,36 +214,34 @@ static av_cold void uninit(AVFilterContext *ctx)
     free_filter_param(&unsharp->chroma);
 }
 
-static int end_frame(AVFilterLink *link)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
 {
     UnsharpContext *unsharp = link->dst->priv;
-    AVFilterBufferRef *in  = link->cur_buf;
-    AVFilterBufferRef *out = link->dst->outputs[0]->out_buf;
+    AVFilterLink *outlink   = link->dst->outputs[0];
+    AVFilterBufferRef *out;
     int cw = SHIFTUP(link->w, unsharp->hsub);
     int ch = SHIFTUP(link->h, unsharp->vsub);
-    int ret;
+
+    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    if (!out) {
+        avfilter_unref_bufferp(&in);
+        return AVERROR(ENOMEM);
+    }
+    avfilter_copy_buffer_ref_props(out, in);
 
     apply_unsharp(out->data[0], out->linesize[0], in->data[0], in->linesize[0], link->w, link->h, &unsharp->luma);
     apply_unsharp(out->data[1], out->linesize[1], in->data[1], in->linesize[1], cw,      ch,      &unsharp->chroma);
     apply_unsharp(out->data[2], out->linesize[2], in->data[2], in->linesize[2], cw,      ch,      &unsharp->chroma);
 
-    if ((ret = ff_draw_slice(link->dst->outputs[0], 0, link->h, 1)) < 0 ||
-        (ret = ff_end_frame(link->dst->outputs[0])) < 0)
-        return ret;
-    return 0;
-}
-
-static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
+    avfilter_unref_bufferp(&in);
+    return ff_filter_frame(outlink, out);
 }
 
 static const AVFilterPad avfilter_vf_unsharp_inputs[] = {
     {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
-        .draw_slice   = draw_slice,
-        .end_frame    = end_frame,
+        .filter_frame = filter_frame,
         .config_props = config_props,
         .min_perms    = AV_PERM_READ,
     },
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index f12290a..5e6e965 100644
--- a/libavfilter/vf_vflip.c
+++ b/libavfilter/vf_vflip.c
@@ -69,41 +69,28 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
     return picref;
 }
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
 {
     FlipContext *flip = link->dst->priv;
-    AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
     int i;
 
-    if (!outpicref)
-        return AVERROR(ENOMEM);
-
     for (i = 0; i < 4; i ++) {
         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
 
-        if (outpicref->data[i]) {
-            outpicref->data[i] += ((link->h >> vsub)-1) * outpicref->linesize[i];
-            outpicref->linesize[i] = -outpicref->linesize[i];
+        if (frame->data[i]) {
+            frame->data[i] += ((link->h >> vsub)-1) * frame->linesize[i];
+            frame->linesize[i] = -frame->linesize[i];
         }
     }
 
-    return ff_start_frame(link->dst->outputs[0], outpicref);
-}
-
-static int draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    AVFilterContext *ctx = link->dst;
-
-    return ff_draw_slice(ctx->outputs[0], link->h - (y+h), h, -1 * slice_dir);
+    return ff_filter_frame(link->dst->outputs[0], frame);
 }
-
 static const AVFilterPad avfilter_vf_vflip_inputs[] = {
     {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = get_video_buffer,
-        .start_frame      = start_frame,
-        .draw_slice       = draw_slice,
+        .filter_frame     = filter_frame,
         .config_props     = config_input,
     },
     { NULL }
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index 1c605d9..db9c71c 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -202,19 +202,14 @@ static int return_frame(AVFilterContext *ctx, int is_second)
         } else {
             yadif->out->pts = AV_NOPTS_VALUE;
         }
-        ret = ff_start_frame(ctx->outputs[0], yadif->out);
-        if (ret < 0)
-            return ret;
     }
-    if ((ret = ff_draw_slice(ctx->outputs[0], 0, link->h, 1)) < 0 ||
-        (ret = ff_end_frame(ctx->outputs[0])) < 0)
-        return ret;
+    ret = ff_filter_frame(ctx->outputs[0], yadif->out);
 
     yadif->frame_pending = (yadif->mode&1) && !is_second;
-    return 0;
+    return ret;
 }
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref)
 {
     AVFilterContext *ctx = link->dst;
     YADIFContext *yadif = ctx->priv;
@@ -227,7 +222,6 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
     yadif->prev = yadif->cur;
     yadif->cur  = yadif->next;
     yadif->next = picref;
-    link->cur_buf = NULL;
 
     if (!yadif->cur)
         return 0;
@@ -240,7 +234,7 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
         avfilter_unref_bufferp(&yadif->prev);
         if (yadif->out->pts != AV_NOPTS_VALUE)
             yadif->out->pts *= 2;
-        return ff_start_frame(ctx->outputs[0], yadif->out);
+        return ff_filter_frame(ctx->outputs[0], yadif->out);
     }
 
     if (!yadif->prev &&
@@ -258,26 +252,7 @@ static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
     if (yadif->out->pts != AV_NOPTS_VALUE)
         yadif->out->pts *= 2;
 
-    return ff_start_frame(ctx->outputs[0], yadif->out);
-}
-
-static int end_frame(AVFilterLink *link)
-{
-    AVFilterContext *ctx = link->dst;
-    YADIFContext *yadif = ctx->priv;
-
-    if (!yadif->out)
-        return 0;
-
-    if (yadif->auto_enable && !yadif->cur->video->interlaced) {
-        int ret = ff_draw_slice(ctx->outputs[0], 0, link->h, 1);
-        if (ret >= 0)
-            ret = ff_end_frame(ctx->outputs[0]);
-        return ret;
-    }
-
-    return_frame(ctx, 0);
-    return 0;
+    return return_frame(ctx, 0);
 }
 
 static int request_frame(AVFilterLink *link)
@@ -307,8 +282,7 @@ static int request_frame(AVFilterLink *link)
 
             next->pts = yadif->next->pts * 2 - yadif->cur->pts;
 
-            start_frame(link->src->inputs[0], next);
-            end_frame(link->src->inputs[0]);
+            filter_frame(link->src->inputs[0], next);
             yadif->eof = 1;
         } else if (ret < 0) {
             return ret;
@@ -409,11 +383,6 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return 0;
-}
-
 static int config_props(AVFilterLink *link)
 {
     link->time_base.num = link->src->inputs[0]->time_base.num;
@@ -428,10 +397,8 @@ static const AVFilterPad avfilter_vf_yadif_inputs[] = {
     {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
-        .start_frame      = start_frame,
         .get_video_buffer = get_video_buffer,
-        .draw_slice       = null_draw_slice,
-        .end_frame        = end_frame,
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/video.c b/libavfilter/video.c
index 49091ad..cb68ca4 100644
--- a/libavfilter/video.c
+++ b/libavfilter/video.c
@@ -163,213 +163,3 @@ AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms, int w, int
 
     return ret;
 }
-
-int ff_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
-{
-    AVFilterBufferRef *buf_out = avfilter_ref_buffer(picref, ~0);
-    if (!buf_out)
-        return AVERROR(ENOMEM);
-    return ff_start_frame(link->dst->outputs[0], buf_out);
-}
-
-// for filters that support (but don't require) outpic==inpic
-int ff_inplace_start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
-{
-    AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpicref = NULL, *for_next_filter;
-    int ret = 0;
-
-    if ((inpicref->perms & AV_PERM_WRITE) && !(inpicref->perms & AV_PERM_PRESERVE)) {
-        outpicref = avfilter_ref_buffer(inpicref, ~0);
-        if (!outpicref)
-            return AVERROR(ENOMEM);
-    } else {
-        outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
-        if (!outpicref)
-            return AVERROR(ENOMEM);
-
-        avfilter_copy_buffer_ref_props(outpicref, inpicref);
-        outpicref->video->w = outlink->w;
-        outpicref->video->h = outlink->h;
-    }
-
-    for_next_filter = avfilter_ref_buffer(outpicref, ~0);
-    if (for_next_filter)
-        ret = ff_start_frame(outlink, for_next_filter);
-    else
-        ret = AVERROR(ENOMEM);
-
-    if (ret < 0) {
-        avfilter_unref_bufferp(&outpicref);
-        return ret;
-    }
-
-    outlink->out_buf = outpicref;
-    return 0;
-}
-
-static int default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
-{
-    AVFilterLink *outlink = NULL;
-
-    if (inlink->dst->nb_outputs)
-        outlink = inlink->dst->outputs[0];
-
-    if (outlink) {
-        AVFilterBufferRef *buf_out;
-        outlink->out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
-        if (!outlink->out_buf)
-            return AVERROR(ENOMEM);
-
-        avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
-        buf_out = avfilter_ref_buffer(outlink->out_buf, ~0);
-        if (!buf_out)
-            return AVERROR(ENOMEM);
-
-        return ff_start_frame(outlink, buf_out);
-    }
-    return 0;
-}
-
-static void clear_link(AVFilterLink *link)
-{
-    avfilter_unref_bufferp(&link->cur_buf);
-    avfilter_unref_bufferp(&link->src_buf);
-    avfilter_unref_bufferp(&link->out_buf);
-}
-
-/* XXX: should we do the duplicating of the picture ref here, instead of
- * forcing the source filter to do it? */
-int ff_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
-{
-    int (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
-    AVFilterPad *dst = link->dstpad;
-    int ret, perms = picref->perms;
-
-    FF_DPRINTF_START(NULL, start_frame); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " "); ff_dlog_ref(NULL, picref, 1);
-
-    if (!(start_frame = dst->start_frame))
-        start_frame = default_start_frame;
-
-    if (picref->linesize[0] < 0)
-        perms |= AV_PERM_NEG_LINESIZES;
-    /* prepare to copy the picture if it has insufficient permissions */
-    if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) {
-        av_log(link->dst, AV_LOG_DEBUG,
-                "frame copy needed (have perms %x, need %x, reject %x)\n",
-                picref->perms,
-                link->dstpad->min_perms, link->dstpad->rej_perms);
-
-        link->cur_buf = ff_get_video_buffer(link, dst->min_perms, link->w, link->h);
-        if (!link->cur_buf) {
-            avfilter_unref_bufferp(&picref);
-            return AVERROR(ENOMEM);
-        }
-
-        link->src_buf = picref;
-        avfilter_copy_buffer_ref_props(link->cur_buf, link->src_buf);
-    }
-    else
-        link->cur_buf = picref;
-
-    ret = start_frame(link, link->cur_buf);
-    if (ret < 0)
-        clear_link(link);
-
-    return ret;
-}
-
-int ff_null_end_frame(AVFilterLink *link)
-{
-    return ff_end_frame(link->dst->outputs[0]);
-}
-
-static int default_end_frame(AVFilterLink *inlink)
-{
-    AVFilterLink *outlink = NULL;
-
-    if (inlink->dst->nb_outputs)
-        outlink = inlink->dst->outputs[0];
-
-    if (outlink) {
-        return ff_end_frame(outlink);
-    }
-    return 0;
-}
-
-int ff_end_frame(AVFilterLink *link)
-{
-    int (*end_frame)(AVFilterLink *);
-    int ret;
-
-    if (!(end_frame = link->dstpad->end_frame))
-        end_frame = default_end_frame;
-
-    ret = end_frame(link);
-
-    clear_link(link);
-
-    return ret;
-}
-
-int ff_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    return ff_draw_slice(link->dst->outputs[0], y, h, slice_dir);
-}
-
-static int default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
-{
-    AVFilterLink *outlink = NULL;
-
-    if (inlink->dst->nb_outputs)
-        outlink = inlink->dst->outputs[0];
-
-    if (outlink)
-        return ff_draw_slice(outlink, y, h, slice_dir);
-    return 0;
-}
-
-int ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
-{
-    uint8_t *src[4], *dst[4];
-    int i, j, vsub, ret;
-    int (*draw_slice)(AVFilterLink *, int, int, int);
-
-    FF_DPRINTF_START(NULL, draw_slice); ff_dlog_link(NULL, link, 0); av_dlog(NULL, " y:%d h:%d dir:%d\n", y, h, slice_dir);
-
-    /* copy the slice if needed for permission reasons */
-    if (link->src_buf) {
-        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
-        vsub = desc->log2_chroma_h;
-
-        for (i = 0; i < 4; i++) {
-            if (link->src_buf->data[i]) {
-                src[i] = link->src_buf-> data[i] +
-                    (y >> (i==1 || i==2 ? vsub : 0)) * link->src_buf-> linesize[i];
-                dst[i] = link->cur_buf->data[i] +
-                    (y >> (i==1 || i==2 ? vsub : 0)) * link->cur_buf->linesize[i];
-            } else
-                src[i] = dst[i] = NULL;
-        }
-
-        for (i = 0; i < 4; i++) {
-            int planew =
-                av_image_get_linesize(link->format, link->cur_buf->video->w, i);
-
-            if (!src[i]) continue;
-
-            for (j = 0; j < h >> (i==1 || i==2 ? vsub : 0); j++) {
-                memcpy(dst[i], src[i], planew);
-                src[i] += link->src_buf->linesize[i];
-                dst[i] += link->cur_buf->linesize[i];
-            }
-        }
-    }
-
-    if (!(draw_slice = link->dstpad->draw_slice))
-        draw_slice = default_draw_slice;
-    ret = draw_slice(link, y, h, slice_dir);
-    if (ret < 0)
-        clear_link(link);
-    return ret;
-}
diff --git a/libavfilter/video.h b/libavfilter/video.h
index 348240c..be93810 100644
--- a/libavfilter/video.h
+++ b/libavfilter/video.h
@@ -39,51 +39,4 @@ AVFilterBufferRef *ff_null_get_video_buffer(AVFilterLink *link, int perms, int w
 AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms,
                                        int w, int h);
 
-int ff_inplace_start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
-int ff_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
-int ff_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
-int ff_null_end_frame(AVFilterLink *link);
-
-/**
- * Notify the next filter of the start of a frame.
- *
- * @param link   the output link the frame will be sent over
- * @param picref A reference to the frame about to be sent. The data for this
- *               frame need only be valid once draw_slice() is called for that
- *               portion. The receiving filter will free this reference when
- *               it no longer needs it.
- *
- * @return >= 0 on success, a negative AVERROR on error. This function will
- * unreference picref in case of error.
- */
-int ff_start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
-
-/**
- * Notify the next filter that the current frame has finished.
- *
- * @param link the output link the frame was sent over
- *
- * @return >= 0 on success, a negative AVERROR on error
- */
-int ff_end_frame(AVFilterLink *link);
-
-/**
- * Send a slice to the next filter.
- *
- * Slices have to be provided in sequential order, either in
- * top-bottom or bottom-top order. If slices are provided in
- * non-sequential order the behavior of the function is undefined.
- *
- * @param link the output link over which the frame is being sent
- * @param y    offset in pixels from the top of the image for this slice
- * @param h    height of this slice in pixels
- * @param slice_dir the assumed direction for sending slices,
- *             from the top slice to the bottom slice if the value is 1,
- *             from the bottom slice to the top slice if the value is -1,
- *             for other values the behavior of the function is undefined.
- *
- * @return >= 0 on success, a negative AVERROR on error.
- */
-int ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
-
 #endif /* AVFILTER_VIDEO_H */
diff --git a/libavfilter/vsink_nullsink.c b/libavfilter/vsink_nullsink.c
index b10ee62..71d2b3e 100644
--- a/libavfilter/vsink_nullsink.c
+++ b/libavfilter/vsink_nullsink.c
@@ -20,13 +20,9 @@
 #include "internal.h"
 #include "libavutil/internal.h"
 
-static int start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
-{
-    return 0;
-}
-
-static int end_frame(AVFilterLink *link)
+static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
 {
+    avfilter_unref_bufferp(&frame);
     return 0;
 }
 
@@ -34,8 +30,7 @@ static const AVFilterPad avfilter_vsink_nullsink_inputs[] = {
     {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
-        .start_frame = start_frame,
-        .end_frame   = end_frame,
+        .filter_frame = filter_frame,
     },
     { NULL },
 };
diff --git a/libavfilter/vsrc_color.c b/libavfilter/vsrc_color.c
index 2bb07bf..c0a4e1c 100644
--- a/libavfilter/vsrc_color.c
+++ b/libavfilter/vsrc_color.c
@@ -147,8 +147,6 @@ static int color_request_frame(AVFilterLink *link)
 {
     ColorContext *color = link->src->priv;
     AVFilterBufferRef *picref = ff_get_video_buffer(link, AV_PERM_WRITE, color->w, color->h);
-    AVFilterBufferRef *buf_out;
-    int ret;
 
     if (!picref)
         return AVERROR(ENOMEM);
@@ -157,29 +155,10 @@ static int color_request_frame(AVFilterLink *link)
     picref->pts                 = color->pts++;
     picref->pos                 = -1;
 
-    buf_out = avfilter_ref_buffer(picref, ~0);
-    if (!buf_out) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    ret = ff_start_frame(link, buf_out);
-    if (ret < 0)
-        goto fail;
-
     ff_draw_rectangle(picref->data, picref->linesize,
                       color->line, color->line_step, color->hsub, color->vsub,
                       0, 0, color->w, color->h);
-    ret = ff_draw_slice(link, 0, color->h, 1);
-    if (ret < 0)
-        goto fail;
-
-    ret = ff_end_frame(link);
-
-fail:
-    avfilter_unref_buffer(picref);
-
-    return ret;
+    return ff_filter_frame(link, picref);
 }
 
 static const AVFilterPad avfilter_vsrc_color_outputs[] = {
diff --git a/libavfilter/vsrc_movie.c b/libavfilter/vsrc_movie.c
index 7918676..e6185d6 100644
--- a/libavfilter/vsrc_movie.c
+++ b/libavfilter/vsrc_movie.c
@@ -279,7 +279,6 @@ static int movie_get_frame(AVFilterLink *outlink)
 
 static int request_frame(AVFilterLink *outlink)
 {
-    AVFilterBufferRef *outpicref;
     MovieContext *movie = outlink->src->priv;
     int ret;
 
@@ -288,23 +287,8 @@ static int request_frame(AVFilterLink *outlink)
     if ((ret = movie_get_frame(outlink)) < 0)
         return ret;
 
-    outpicref = avfilter_ref_buffer(movie->picref, ~0);
-    if (!outpicref) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
-
-    ret = ff_start_frame(outlink, outpicref);
-    if (ret < 0)
-        goto fail;
-
-    ret = ff_draw_slice(outlink, 0, outlink->h, 1);
-    if (ret < 0)
-        goto fail;
-
-    ret = ff_end_frame(outlink);
-fail:
-    avfilter_unref_bufferp(&movie->picref);
+    ret = ff_filter_frame(outlink, movie->picref);
+    movie->picref = NULL;
 
     return ret;
 }
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index b81611d..632bd27 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -131,7 +131,6 @@ static int request_frame(AVFilterLink *outlink)
 {
     TestSourceContext *test = outlink->src->priv;
     AVFilterBufferRef *picref;
-    int ret;
 
     if (test->max_pts >= 0 && test->pts > test->max_pts)
         return AVERROR_EOF;
@@ -148,12 +147,7 @@ static int request_frame(AVFilterLink *outlink)
     test->nb_frame++;
     test->fill_picture_fn(outlink->src, picref);
 
-    if ((ret = ff_start_frame(outlink, picref)) < 0 ||
-        (ret = ff_draw_slice(outlink, 0, test->h, 1)) < 0 ||
-        (ret = ff_end_frame(outlink)) < 0)
-        return ret;
-
-    return 0;
+    return ff_filter_frame(outlink, picref);
 }
 
 #if CONFIG_TESTSRC_FILTER



More information about the ffmpeg-cvslog mailing list