diff --git a/doc/filters.texi b/doc/filters.texi
index b170f850e7eed61e722e738efc3c021f91948633..88a52acca2d42bbd1eac2bde54f788080332a918 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -2086,9 +2086,6 @@ pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
 @item n
 the number of input frame, starting from 0
 
-@item pos
-the position in the file of the input frame, NAN if unknown
-
 @item t
 timestamp expressed in seconds, NAN if the input timestamp is unknown
 
diff --git a/ffmpeg.c b/ffmpeg.c
index 07fde7a577bdbd43440e271a3e9568e1a730c99b..20f016cb526c768e1105df61beb73a855ec039ea 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -1627,8 +1627,8 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
                                               (AVRational){1, ist->st->codec->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,
                                               (AVRational){1, ist->st->codec->sample_rate});
     for (i = 0; i < ist->nb_filters; i++)
-        av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame,
-                               AV_BUFFERSRC_FLAG_PUSH);
+        av_buffersrc_write_frame(ist->filters[i]->filter, decoded_frame);
+        /* TODO re-add AV_BUFFERSRC_FLAG_PUSH */
 
     decoded_frame->pts = AV_NOPTS_VALUE;
 
@@ -1737,7 +1737,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
                                  AV_BUFFERSRC_FLAG_NO_COPY |
                                  AV_BUFFERSRC_FLAG_PUSH);
         } else
-        if(av_buffersrc_add_frame(ist->filters[i]->filter, decoded_frame, AV_BUFFERSRC_FLAG_PUSH)<0) {
+        if(av_buffersrc_add_frame_flags(ist->filters[i]->filter, decoded_frame, AV_BUFFERSRC_FLAG_PUSH)<0) {
             av_log(NULL, AV_LOG_FATAL, "Failed to inject frame into filter network\n");
             exit(1);
         }
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 43c63cf66077b7bfc429233afb79f4ecc92ea2e1..229ae839c00d6d3776fde34588837580a22504ac 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -33,7 +33,6 @@ OBJS = allfilters.o                                                     \
        avfilter.o                                                       \
        avfiltergraph.o                                                  \
        buffer.o                                                         \
-       buffersink.o                                                     \
        buffersrc.o                                                      \
        drawutils.o                                                      \
        fifo.o                                                           \
@@ -41,7 +40,6 @@ OBJS = allfilters.o                                                     \
        graphdump.o                                                      \
        graphparser.o                                                    \
        sink_buffer.o                                                    \
-       src_buffer.o                                                     \
        transform.o                                                      \
        video.o                                                          \
 
diff --git a/libavfilter/af_aconvert.c b/libavfilter/af_aconvert.c
index e41095f2a526fbfd46eee3015e1c152b1bd419af..2cf12e3308256c1514600f0842ac49bfe111b3c0 100644
--- a/libavfilter/af_aconvert.c
+++ b/libavfilter/af_aconvert.c
@@ -135,23 +135,23 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int  filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
+static int  filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
 {
     AConvertContext *aconvert = inlink->dst->priv;
-    const int n = insamplesref->audio->nb_samples;
+    const int n = insamplesref->nb_samples;
     AVFilterLink *const outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n);
+    AVFrame *outsamplesref = ff_get_audio_buffer(outlink, n);
     int ret;
 
-    swr_convert(aconvert->swr, outsamplesref->data, n,
-                        (void *)insamplesref->data, n);
+    swr_convert(aconvert->swr, outsamplesref->extended_data, n,
+                        (void *)insamplesref->extended_data, n);
 
-    avfilter_copy_buffer_ref_props(outsamplesref, insamplesref);
-    outsamplesref->audio->channels       = outlink->channels;
-    outsamplesref->audio->channel_layout = outlink->channel_layout;
+    av_frame_copy_props(outsamplesref, insamplesref);
+    outsamplesref->channels       = outlink->channels;
+    outsamplesref->channel_layout = outlink->channel_layout;
 
     ret = ff_filter_frame(outlink, outsamplesref);
-    avfilter_unref_buffer(insamplesref);
+    av_frame_free(&insamplesref);
     return ret;
 }
 
@@ -160,7 +160,6 @@ static const AVFilterPad aconvert_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c
index 00a05e2c1eebcb665825b1b4afa9da67f4c8de0f..0e660a3f4c57c711d0ef8e64f508fee5c8083d3d 100644
--- a/libavfilter/af_afade.c
+++ b/libavfilter/af_afade.c
@@ -232,22 +232,22 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AudioFadeContext *afade = inlink->dst->priv;
     AVFilterLink *outlink   = inlink->dst->outputs[0];
-    int nb_samples          = buf->audio->nb_samples;
-    AVFilterBufferRef *out_buf;
+    int nb_samples          = buf->nb_samples;
+    AVFrame *out_buf;
     int64_t cur_sample = av_rescale_q(buf->pts, (AVRational){1, outlink->sample_rate}, outlink->time_base);
 
     if ((!afade->type && (afade->start_sample + afade->nb_samples < cur_sample)) ||
         ( afade->type && (cur_sample + afade->nb_samples < afade->start_sample)))
         return ff_filter_frame(outlink, buf);
 
-    if (buf->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(buf)) {
         out_buf = buf;
     } else {
-        out_buf = ff_get_audio_buffer(inlink, AV_PERM_WRITE, nb_samples);
+        out_buf = ff_get_audio_buffer(inlink, nb_samples);
         if (!out_buf)
             return AVERROR(ENOMEM);
         out_buf->pts = buf->pts;
@@ -256,7 +256,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     if ((!afade->type && (cur_sample + nb_samples < afade->start_sample)) ||
         ( afade->type && (afade->start_sample + afade->nb_samples < cur_sample))) {
         av_samples_set_silence(out_buf->extended_data, 0, nb_samples,
-                               out_buf->audio->channels, out_buf->format);
+                               out_buf->channels, out_buf->format);
     } else {
         int64_t start;
 
@@ -266,13 +266,13 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
             start = afade->start_sample + afade->nb_samples - cur_sample;
 
         afade->fade_samples(out_buf->extended_data, buf->extended_data,
-                            nb_samples, buf->audio->channels,
+                            nb_samples, buf->channels,
                             afade->type ? -1 : 1, start,
                             afade->nb_samples, afade->curve);
     }
 
     if (buf != out_buf)
-        avfilter_unref_buffer(buf);
+        av_frame_free(&buf);
 
     return ff_filter_frame(outlink, out_buf);
 }
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
index 2d68ea6126d0e734a29f992586e993f66c2f3cba..b26141d14f3c1198f60d9b2828ca55bd951047b3 100644
--- a/libavfilter/af_amerge.c
+++ b/libavfilter/af_amerge.c
@@ -219,14 +219,14 @@ static inline void copy_samples(int nb_inputs, struct amerge_input in[],
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     AVFilterContext *ctx = inlink->dst;
     AMergeContext *am = ctx->priv;
     AVFilterLink *const outlink = ctx->outputs[0];
     int input_number;
     int nb_samples, ns, i;
-    AVFilterBufferRef *outbuf, *inbuf[SWR_CH_MAX];
+    AVFrame *outbuf, *inbuf[SWR_CH_MAX];
     uint8_t *ins[SWR_CH_MAX], *outs;
 
     for (input_number = 0; input_number < am->nb_inputs; input_number++)
@@ -235,39 +235,40 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
     av_assert1(input_number < am->nb_inputs);
     if (ff_bufqueue_is_full(&am->in[input_number].queue)) {
         av_log(ctx, AV_LOG_ERROR, "Buffer queue overflow\n");
-        avfilter_unref_buffer(insamples);
+        av_frame_free(&insamples);
         return AVERROR(ENOMEM);
     }
-    ff_bufqueue_add(ctx, &am->in[input_number].queue, insamples);
-    am->in[input_number].nb_samples += insamples->audio->nb_samples;
+    ff_bufqueue_add(ctx, &am->in[input_number].queue, av_frame_clone(insamples));
+    am->in[input_number].nb_samples += insamples->nb_samples;
+    av_frame_free(&insamples);
     nb_samples = am->in[0].nb_samples;
     for (i = 1; i < am->nb_inputs; i++)
         nb_samples = FFMIN(nb_samples, am->in[i].nb_samples);
     if (!nb_samples)
         return 0;
 
-    outbuf = ff_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE, nb_samples);
+    outbuf = ff_get_audio_buffer(ctx->outputs[0], nb_samples);
     outs = outbuf->data[0];
     for (i = 0; i < am->nb_inputs; i++) {
         inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0);
         ins[i] = inbuf[i]->data[0] +
                  am->in[i].pos * am->in[i].nb_ch * am->bps;
     }
-    avfilter_copy_buffer_ref_props(outbuf, inbuf[0]);
+    av_frame_copy_props(outbuf, inbuf[0]);
     outbuf->pts = inbuf[0]->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
                   inbuf[0]->pts +
                   av_rescale_q(am->in[0].pos,
                                (AVRational){ 1, ctx->inputs[0]->sample_rate },
                                ctx->outputs[0]->time_base);
 
-    outbuf->audio->nb_samples     = nb_samples;
-    outbuf->audio->channel_layout = outlink->channel_layout;
-    outbuf->audio->channels       = outlink->channels;
+    outbuf->nb_samples     = nb_samples;
+    outbuf->channel_layout = outlink->channel_layout;
+    outbuf->channels       = outlink->channels;
 
     while (nb_samples) {
         ns = nb_samples;
         for (i = 0; i < am->nb_inputs; i++)
-            ns = FFMIN(ns, inbuf[i]->audio->nb_samples - am->in[i].pos);
+            ns = FFMIN(ns, inbuf[i]->nb_samples - am->in[i].pos);
         /* Unroll the most common sample formats: speed +~350% for the loop,
            +~13% overall (including two common decoders) */
         switch (am->bps) {
@@ -289,9 +290,9 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
         for (i = 0; i < am->nb_inputs; i++) {
             am->in[i].nb_samples -= ns;
             am->in[i].pos += ns;
-            if (am->in[i].pos == inbuf[i]->audio->nb_samples) {
+            if (am->in[i].pos == inbuf[i]->nb_samples) {
                 am->in[i].pos = 0;
-                avfilter_unref_buffer(inbuf[i]);
+                av_frame_free(&inbuf[i]);
                 ff_bufqueue_get(&am->in[i].queue);
                 inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0);
                 ins[i] = inbuf[i] ? inbuf[i]->data[0] : NULL;
@@ -322,7 +323,6 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
             .name             = name,
             .type             = AVMEDIA_TYPE_AUDIO,
             .filter_frame     = filter_frame,
-            .min_perms        = AV_PERM_READ | AV_PERM_PRESERVE,
         };
         if (!name)
             return AVERROR(ENOMEM);
diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c
index aeefff8065173c6b2b7194200a5aaeff18c17542..dcb24b0f3aaedf25c4ba61555febe621e264aa72 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -270,18 +270,18 @@ static int output_frame(AVFilterLink *outlink, int nb_samples)
 {
     AVFilterContext *ctx = outlink->src;
     MixContext      *s = ctx->priv;
-    AVFilterBufferRef *out_buf, *in_buf;
+    AVFrame *out_buf, *in_buf;
     int i;
 
     calculate_scales(s, nb_samples);
 
-    out_buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
+    out_buf = ff_get_audio_buffer(outlink, nb_samples);
     if (!out_buf)
         return AVERROR(ENOMEM);
 
-    in_buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
+    in_buf = ff_get_audio_buffer(outlink, nb_samples);
     if (!in_buf) {
-        avfilter_unref_buffer(out_buf);
+        av_frame_free(&out_buf);
         return AVERROR(ENOMEM);
     }
 
@@ -303,7 +303,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples)
             }
         }
     }
-    avfilter_unref_buffer(in_buf);
+    av_frame_free(&in_buf);
 
     out_buf->pts = s->next_pts;
     if (s->next_pts != AV_NOPTS_VALUE)
@@ -450,7 +450,7 @@ static int request_frame(AVFilterLink *outlink)
     return output_frame(outlink, available_samples);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     MixContext       *s = ctx->priv;
@@ -469,16 +469,16 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     if (i == 0) {
         int64_t pts = av_rescale_q(buf->pts, inlink->time_base,
                                    outlink->time_base);
-        ret = frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts);
+        ret = frame_list_add_frame(s->frame_list, buf->nb_samples, pts);
         if (ret < 0)
             goto fail;
     }
 
     ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data,
-                              buf->audio->nb_samples);
+                              buf->nb_samples);
 
 fail:
-    avfilter_unref_buffer(buf);
+    av_frame_free(&buf);
 
     return ret;
 }
diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c
index 18a017068821f8291a4fb8f5803c57cb1e373dd9..2afd3a860d773e9fd41710beb1704b41b063852d 100644
--- a/libavfilter/af_apad.c
+++ b/libavfilter/af_apad.c
@@ -77,15 +77,15 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     APadContext *apad = ctx->priv;
 
     if (apad->whole_len)
-        apad->whole_len -= frame->audio->nb_samples;
+        apad->whole_len -= frame->nb_samples;
 
-    apad->next_pts = frame->pts + av_rescale_q(frame->audio->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
+    apad->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
     return ff_filter_frame(ctx->outputs[0], frame);
 }
 
@@ -99,7 +99,7 @@ static int request_frame(AVFilterLink *outlink)
 
     if (ret == AVERROR_EOF) {
         int n_out = apad->packet_size;
-        AVFilterBufferRef *outsamplesref;
+        AVFrame *outsamplesref;
 
         if (apad->whole_len > 0) {
             apad->pad_len = apad->whole_len;
@@ -113,16 +113,16 @@ static int request_frame(AVFilterLink *outlink)
         if(!n_out)
             return AVERROR_EOF;
 
-        outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n_out);
+        outsamplesref = ff_get_audio_buffer(outlink, n_out);
         if (!outsamplesref)
             return AVERROR(ENOMEM);
 
-        av_assert0(outsamplesref->audio->sample_rate == outlink->sample_rate);
-        av_assert0(outsamplesref->audio->nb_samples  == n_out);
+        av_assert0(outsamplesref->sample_rate == outlink->sample_rate);
+        av_assert0(outsamplesref->nb_samples  == n_out);
 
         av_samples_set_silence(outsamplesref->extended_data, 0,
                                n_out,
-                               outsamplesref->audio->channels,
+                               outsamplesref->channels,
                                outsamplesref->format);
 
         outsamplesref->pts = apad->next_pts;
diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
index 66a8a539f76b2d1eed058879775b70e55e863204..6e0d679369f19bcadb558092fef18bed6540c180 100644
--- a/libavfilter/af_aresample.c
+++ b/libavfilter/af_aresample.c
@@ -174,23 +174,23 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
 {
     AResampleContext *aresample = inlink->dst->priv;
-    const int n_in  = insamplesref->audio->nb_samples;
+    const int n_in  = insamplesref->nb_samples;
     int n_out       = n_in * aresample->ratio * 2 + 256;
     AVFilterLink *const outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n_out);
+    AVFrame *outsamplesref = ff_get_audio_buffer(outlink, n_out);
     int ret;
 
     if(!outsamplesref)
         return AVERROR(ENOMEM);
 
-    avfilter_copy_buffer_ref_props(outsamplesref, insamplesref);
+    av_frame_copy_props(outsamplesref, insamplesref);
     outsamplesref->format                = outlink->format;
-    outsamplesref->audio->channels       = outlink->channels;
-    outsamplesref->audio->channel_layout = outlink->channel_layout;
-    outsamplesref->audio->sample_rate    = outlink->sample_rate;
+    outsamplesref->channels              = outlink->channels;
+    outsamplesref->channel_layout        = outlink->channel_layout;
+    outsamplesref->sample_rate           = outlink->sample_rate;
 
     if(insamplesref->pts != AV_NOPTS_VALUE) {
         int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den);
@@ -203,16 +203,16 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamplesref)
     n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out,
                                  (void *)insamplesref->extended_data, n_in);
     if (n_out <= 0) {
-        avfilter_unref_buffer(outsamplesref);
-        avfilter_unref_buffer(insamplesref);
+        av_frame_free(&outsamplesref);
+        av_frame_free(&insamplesref);
         return 0;
     }
 
-    outsamplesref->audio->nb_samples  = n_out;
+    outsamplesref->nb_samples  = n_out;
 
     ret = ff_filter_frame(outlink, outsamplesref);
     aresample->req_fullfilled= 1;
-    avfilter_unref_buffer(insamplesref);
+    av_frame_free(&insamplesref);
     return ret;
 }
 
@@ -229,20 +229,20 @@ static int request_frame(AVFilterLink *outlink)
     }while(!aresample->req_fullfilled && ret>=0);
 
     if (ret == AVERROR_EOF) {
-        AVFilterBufferRef *outsamplesref;
+        AVFrame *outsamplesref;
         int n_out = 4096;
 
-        outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n_out);
+        outsamplesref = ff_get_audio_buffer(outlink, n_out);
         if (!outsamplesref)
             return AVERROR(ENOMEM);
         n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, 0, 0);
         if (n_out <= 0) {
-            avfilter_unref_buffer(outsamplesref);
+            av_frame_free(&outsamplesref);
             return (n_out == 0) ? AVERROR_EOF : n_out;
         }
 
-        outsamplesref->audio->sample_rate = outlink->sample_rate;
-        outsamplesref->audio->nb_samples  = n_out;
+        outsamplesref->sample_rate = outlink->sample_rate;
+        outsamplesref->nb_samples  = n_out;
 #if 0
         outsamplesref->pts = aresample->next_pts;
         if(aresample->next_pts != AV_NOPTS_VALUE)
@@ -263,7 +263,6 @@ static const AVFilterPad aresample_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL },
 };
diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c
index ee80c1c1dba0466c9ee4ba0aad66a0d58bf78169..f995ce98dbaeca047fbecae9745032d618724d7a 100644
--- a/libavfilter/af_asetnsamples.c
+++ b/libavfilter/af_asetnsamples.c
@@ -93,7 +93,7 @@ static int config_props_output(AVFilterLink *outlink)
 static int push_samples(AVFilterLink *outlink)
 {
     ASNSContext *asns = outlink->src->priv;
-    AVFilterBufferRef *outsamples = NULL;
+    AVFrame *outsamples = NULL;
     int nb_out_samples, nb_pad_samples;
 
     if (asns->pad) {
@@ -107,7 +107,7 @@ static int push_samples(AVFilterLink *outlink)
     if (!nb_out_samples)
         return 0;
 
-    outsamples = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_out_samples);
+    outsamples = ff_get_audio_buffer(outlink, nb_out_samples);
     av_assert0(outsamples);
 
     av_audio_fifo_read(asns->fifo,
@@ -117,9 +117,9 @@ static int push_samples(AVFilterLink *outlink)
         av_samples_set_silence(outsamples->extended_data, nb_out_samples - nb_pad_samples,
                                nb_pad_samples, av_get_channel_layout_nb_channels(outlink->channel_layout),
                                outlink->format);
-    outsamples->audio->nb_samples     = nb_out_samples;
-    outsamples->audio->channel_layout = outlink->channel_layout;
-    outsamples->audio->sample_rate    = outlink->sample_rate;
+    outsamples->nb_samples     = nb_out_samples;
+    outsamples->channel_layout = outlink->channel_layout;
+    outsamples->sample_rate    = outlink->sample_rate;
     outsamples->pts = asns->next_out_pts;
 
     if (asns->next_out_pts != AV_NOPTS_VALUE)
@@ -130,13 +130,13 @@ static int push_samples(AVFilterLink *outlink)
     return nb_out_samples;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     AVFilterContext *ctx = inlink->dst;
     ASNSContext *asns = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
     int ret;
-    int nb_samples = insamples->audio->nb_samples;
+    int nb_samples = insamples->nb_samples;
 
     if (av_audio_fifo_space(asns->fifo) < nb_samples) {
         av_log(ctx, AV_LOG_DEBUG, "No space for %d samples, stretching audio fifo\n", nb_samples);
@@ -150,7 +150,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
     av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples);
     if (asns->next_out_pts == AV_NOPTS_VALUE)
         asns->next_out_pts = insamples->pts;
-    avfilter_unref_buffer(insamples);
+    av_frame_free(&insamples);
 
     while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples)
         push_samples(outlink);
@@ -177,10 +177,10 @@ static int request_frame(AVFilterLink *outlink)
 
 static const AVFilterPad asetnsamples_inputs[] = {
     {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_AUDIO,
-        .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ | AV_PERM_WRITE,
+        .name           = "default",
+        .type           = AVMEDIA_TYPE_AUDIO,
+        .filter_frame   = filter_frame,
+        .needs_writable = 1,
     },
     {  NULL }
 };
diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c
index 7e7543f672ccc1c0167bf8327686ea64b245e92b..f53584ec564ea8d0da12d93df05dcbcc17579420 100644
--- a/libavfilter/af_ashowinfo.c
+++ b/libavfilter/af_ashowinfo.c
@@ -55,16 +55,16 @@ static void uninit(AVFilterContext *ctx)
     av_freep(&s->plane_checksums);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     AShowInfoContext *s  = ctx->priv;
     char chlayout_str[128];
     uint32_t checksum = 0;
-    int channels    = av_get_channel_layout_nb_channels(buf->audio->channel_layout);
+    int channels    = av_get_channel_layout_nb_channels(buf->channel_layout);
     int planar      = av_sample_fmt_is_planar(buf->format);
     int block_align = av_get_bytes_per_sample(buf->format) * (planar ? 1 : channels);
-    int data_size   = buf->audio->nb_samples * block_align;
+    int data_size   = buf->nb_samples * block_align;
     int planes      = planar ? channels : 1;
     int i;
     void *tmp_ptr = av_realloc(s->plane_checksums, channels * sizeof(*s->plane_checksums));
@@ -82,7 +82,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     }
 
     av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), -1,
-                                 buf->audio->channel_layout);
+                                 buf->channel_layout);
 
     av_log(ctx, AV_LOG_INFO,
            "n:%"PRIu64" pts:%s pts_time:%s pos:%"PRId64" "
@@ -90,9 +90,9 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
            "checksum:%08X ",
            s->frame,
            av_ts2str(buf->pts), av_ts2timestr(buf->pts, &inlink->time_base),
-           buf->pos,
-           av_get_sample_fmt_name(buf->format), buf->audio->channels, chlayout_str,
-           buf->audio->sample_rate, buf->audio->nb_samples,
+           av_frame_get_pkt_pos(buf),
+           av_get_sample_fmt_name(buf->format), av_frame_get_channels(buf), chlayout_str,
+           buf->sample_rate, buf->nb_samples,
            checksum);
 
     av_log(ctx, AV_LOG_INFO, "plane_checksums: [ ");
@@ -110,7 +110,6 @@ static const AVFilterPad inputs[] = {
         .type             = AVMEDIA_TYPE_AUDIO,
         .get_audio_buffer = ff_null_get_audio_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ,
     },
     { NULL },
 };
diff --git a/libavfilter/af_astreamsync.c b/libavfilter/af_astreamsync.c
index 269ffc10e1b50a7d619b5e601d3fef7ed43f30bf..79f703a5aed4e2096de832482daf56671baa042b 100644
--- a/libavfilter/af_astreamsync.c
+++ b/libavfilter/af_astreamsync.c
@@ -48,7 +48,7 @@ typedef struct {
     AVExpr *expr;
     double var_values[VAR_NB];
     struct buf_queue {
-        AVFilterBufferRef *buf[QUEUE_SIZE];
+        AVFrame *buf[QUEUE_SIZE];
         unsigned tail, nb;
         /* buf[tail] is the oldest,
            buf[(tail + nb) % QUEUE_SIZE] is where the next is added */
@@ -111,16 +111,16 @@ static int send_out(AVFilterContext *ctx, int out_id)
 {
     AStreamSyncContext *as = ctx->priv;
     struct buf_queue *queue = &as->queue[out_id];
-    AVFilterBufferRef *buf = queue->buf[queue->tail];
+    AVFrame *buf = queue->buf[queue->tail];
     int ret;
 
     queue->buf[queue->tail] = NULL;
     as->var_values[VAR_B1 + out_id]++;
-    as->var_values[VAR_S1 + out_id] += buf->audio->nb_samples;
+    as->var_values[VAR_S1 + out_id] += buf->nb_samples;
     if (buf->pts != AV_NOPTS_VALUE)
         as->var_values[VAR_T1 + out_id] =
             av_q2d(ctx->outputs[out_id]->time_base) * buf->pts;
-    as->var_values[VAR_T1 + out_id] += buf->audio->nb_samples /
+    as->var_values[VAR_T1 + out_id] += buf->nb_samples /
                                    (double)ctx->inputs[out_id]->sample_rate;
     ret = ff_filter_frame(ctx->outputs[out_id], buf);
     queue->nb--;
@@ -167,7 +167,7 @@ static int request_frame(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     AVFilterContext *ctx = inlink->dst;
     AStreamSyncContext *as = ctx->priv;
@@ -185,12 +185,10 @@ static const AVFilterPad astreamsync_inputs[] = {
         .name         = "in1",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ | AV_PERM_PRESERVE,
     },{
         .name         = "in2",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ | AV_PERM_PRESERVE,
     },
     { NULL }
 };
diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c
index 500be0f73a832c4f8c3eac2b18d7e76ff3cc2745..c2441a4bc9581aa9d9ae0724eda41bab3deeb598 100644
--- a/libavfilter/af_asyncts.c
+++ b/libavfilter/af_asyncts.c
@@ -152,14 +152,13 @@ static int request_frame(AVFilterLink *link)
             handle_trimming(ctx);
 
         if (nb_samples = get_delay(s)) {
-            AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE,
-                                                         nb_samples);
+            AVFrame *buf = ff_get_audio_buffer(link, nb_samples);
             if (!buf)
                 return AVERROR(ENOMEM);
             ret = avresample_convert(s->avr, buf->extended_data,
                                      buf->linesize[0], nb_samples, NULL, 0, 0);
             if (ret <= 0) {
-                avfilter_unref_bufferp(&buf);
+                av_frame_free(&buf);
                 return (ret < 0) ? ret : AVERROR_EOF;
             }
 
@@ -171,20 +170,20 @@ static int request_frame(AVFilterLink *link)
     return ret;
 }
 
-static int write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf)
+static int write_to_fifo(ASyncContext *s, AVFrame *buf)
 {
     int ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
-                                 buf->linesize[0], buf->audio->nb_samples);
-    avfilter_unref_buffer(buf);
+                                 buf->linesize[0], buf->nb_samples);
+    av_frame_free(&buf);
     return ret;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     ASyncContext       *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    int nb_channels = av_get_channel_layout_nb_channels(buf->audio->channel_layout);
+    int nb_channels = av_get_channel_layout_nb_channels(buf->channel_layout);
     int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts :
                   av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
     int out_size, ret;
@@ -223,8 +222,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     }
 
     if (out_size > 0) {
-        AVFilterBufferRef *buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE,
-                                                         out_size);
+        AVFrame *buf_out = ff_get_audio_buffer(outlink, out_size);
         if (!buf_out) {
             ret = AVERROR(ENOMEM);
             goto fail;
@@ -266,11 +264,11 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 
     s->pts = pts - avresample_get_delay(s->avr);
     ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
-                             buf->linesize[0], buf->audio->nb_samples);
+                             buf->linesize[0], buf->nb_samples);
 
     s->first_frame = 0;
 fail:
-    avfilter_unref_buffer(buf);
+    av_frame_free(&buf);
 
     return ret;
 }
diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c
index d186aafe9cb42fc6569b7db2f32ccde595ea82fb..53bf9e26bfb91f347b75d0949cf58b0aa6e19a6e 100644
--- a/libavfilter/af_atempo.c
+++ b/libavfilter/af_atempo.c
@@ -140,7 +140,7 @@ typedef struct {
 
     // for managing AVFilterPad.request_frame and AVFilterPad.filter_frame
     int request_fulfilled;
-    AVFilterBufferRef *dst_buffer;
+    AVFrame *dst_buffer;
     uint8_t *dst;
     uint8_t *dst_end;
     uint64_t nsamples_in;
@@ -177,7 +177,7 @@ static void yae_clear(ATempoContext *atempo)
     atempo->frag[0].position[0] = -(int64_t)(atempo->window / 2);
     atempo->frag[0].position[1] = -(int64_t)(atempo->window / 2);
 
-    avfilter_unref_bufferp(&atempo->dst_buffer);
+    av_frame_free(&atempo->dst_buffer);
     atempo->dst     = NULL;
     atempo->dst_end = NULL;
 
@@ -1024,8 +1024,8 @@ static void push_samples(ATempoContext *atempo,
                          AVFilterLink *outlink,
                          int n_out)
 {
-    atempo->dst_buffer->audio->sample_rate = outlink->sample_rate;
-    atempo->dst_buffer->audio->nb_samples  = n_out;
+    atempo->dst_buffer->sample_rate = outlink->sample_rate;
+    atempo->dst_buffer->nb_samples  = n_out;
 
     // adjust the PTS:
     atempo->dst_buffer->pts =
@@ -1041,14 +1041,13 @@ static void push_samples(ATempoContext *atempo,
     atempo->nsamples_out += n_out;
 }
 
-static int filter_frame(AVFilterLink *inlink,
-                           AVFilterBufferRef *src_buffer)
+static int filter_frame(AVFilterLink *inlink, AVFrame *src_buffer)
 {
     AVFilterContext  *ctx = inlink->dst;
     ATempoContext *atempo = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
 
-    int n_in = src_buffer->audio->nb_samples;
+    int n_in = src_buffer->nb_samples;
     int n_out = (int)(0.5 + ((double)n_in) / atempo->tempo);
 
     const uint8_t *src = src_buffer->data[0];
@@ -1056,10 +1055,8 @@ static int filter_frame(AVFilterLink *inlink,
 
     while (src < src_end) {
         if (!atempo->dst_buffer) {
-            atempo->dst_buffer = ff_get_audio_buffer(outlink,
-                                                     AV_PERM_WRITE,
-                                                     n_out);
-            avfilter_copy_buffer_ref_props(atempo->dst_buffer, src_buffer);
+            atempo->dst_buffer = ff_get_audio_buffer(outlink, n_out);
+            av_frame_copy_props(atempo->dst_buffer, src_buffer);
 
             atempo->dst = atempo->dst_buffer->data[0];
             atempo->dst_end = atempo->dst + n_out * atempo->stride;
@@ -1074,7 +1071,7 @@ static int filter_frame(AVFilterLink *inlink,
     }
 
     atempo->nsamples_in += n_in;
-    avfilter_unref_bufferp(&src_buffer);
+    av_frame_free(&src_buffer);
     return 0;
 }
 
@@ -1098,9 +1095,7 @@ static int request_frame(AVFilterLink *outlink)
 
         while (err == AVERROR(EAGAIN)) {
             if (!atempo->dst_buffer) {
-                atempo->dst_buffer = ff_get_audio_buffer(outlink,
-                                                         AV_PERM_WRITE,
-                                                         n_max);
+                atempo->dst_buffer = ff_get_audio_buffer(outlink, n_max);
 
                 atempo->dst = atempo->dst_buffer->data[0];
                 atempo->dst_end = atempo->dst + n_max * atempo->stride;
@@ -1116,7 +1111,7 @@ static int request_frame(AVFilterLink *outlink)
             }
         }
 
-        avfilter_unref_bufferp(&atempo->dst_buffer);
+        av_frame_free(&atempo->dst_buffer);
         atempo->dst     = NULL;
         atempo->dst_end = NULL;
 
@@ -1142,7 +1137,6 @@ static const AVFilterPad atempo_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
         .config_props = config_props,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c
index cae3e02b49665be24bd7cdadd609d6e07a6dccd8..6384090d4c9a512a32e54918590b3d41db110b66 100644
--- a/libavfilter/af_biquads.c
+++ b/libavfilter/af_biquads.c
@@ -392,24 +392,24 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     BiquadsContext *p       = inlink->dst->priv;
     AVFilterLink *outlink   = inlink->dst->outputs[0];
-    AVFilterBufferRef *out_buf;
-    int nb_samples = buf->audio->nb_samples;
+    AVFrame *out_buf;
+    int nb_samples = buf->nb_samples;
     int ch;
 
-    if (buf->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(buf)) {
         out_buf = buf;
     } else {
-        out_buf = ff_get_audio_buffer(inlink, AV_PERM_WRITE, nb_samples);
+        out_buf = ff_get_audio_buffer(inlink, nb_samples);
         if (!out_buf)
             return AVERROR(ENOMEM);
         out_buf->pts = buf->pts;
     }
 
-    for (ch = 0; ch < buf->audio->channels; ch++)
+    for (ch = 0; ch < buf->channels; ch++)
         p->filter(buf->extended_data[ch],
                   out_buf->extended_data[ch], nb_samples,
                   &p->cache[ch].i1, &p->cache[ch].i2,
@@ -417,7 +417,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
                   p->b0, p->b1, p->b2, p->a1, p->a2);
 
     if (buf != out_buf)
-        avfilter_unref_buffer(buf);
+        av_frame_free(&buf);
 
     return ff_filter_frame(outlink, out_buf);
 }
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
index 44ed717688d207dba3ba4af0c8831afe6089e1f9..85f333ed81e62293b0e1e90a9a9b5d77f21a9e1b 100644
--- a/libavfilter/af_channelmap.c
+++ b/libavfilter/af_channelmap.c
@@ -312,7 +312,7 @@ static int channelmap_query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int channelmap_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext  *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -330,7 +330,7 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
             uint8_t **new_extended_data =
                 av_mallocz(nch_out * sizeof(*buf->extended_data));
             if (!new_extended_data) {
-                avfilter_unref_buffer(buf);
+                av_frame_free(&buf);
                 return AVERROR(ENOMEM);
             }
             if (buf->extended_data == buf->data) {
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index 9ca9dad45961d8d0830ecf9a4d6604aab15b3172..9bcdc54c347b5175ecb101e9b2b1a0d7e380f72e 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -105,13 +105,13 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     int i, ret = 0;
 
     for (i = 0; i < ctx->nb_outputs; i++) {
-        AVFilterBufferRef *buf_out = avfilter_ref_buffer(buf, ~AV_PERM_WRITE);
+        AVFrame *buf_out = av_frame_clone(buf);
 
         if (!buf_out) {
             ret = AVERROR(ENOMEM);
@@ -119,14 +119,14 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
         }
 
         buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[i];
-        buf_out->audio->channel_layout =
-            av_channel_layout_extract_channel(buf->audio->channel_layout, i);
+        buf_out->channel_layout =
+            av_channel_layout_extract_channel(buf->channel_layout, i);
 
         ret = ff_filter_frame(ctx->outputs[i], buf_out);
         if (ret < 0)
             break;
     }
-    avfilter_unref_buffer(buf);
+    av_frame_free(&buf);
     return ret;
 }
 
diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
index a169d2aaf1f18be3b36b382ebcdfde7c8b429baa..b1d3d6f8712c44e20acc005b08eba255af1cd4a3 100644
--- a/libavfilter/af_earwax.c
+++ b/libavfilter/af_earwax.c
@@ -109,18 +109,18 @@ static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, in
     return out;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     AVFilterLink *outlink = inlink->dst->outputs[0];
     int16_t *taps, *endin, *in, *out;
-    AVFilterBufferRef *outsamples =
-        ff_get_audio_buffer(inlink, AV_PERM_WRITE,
-                                  insamples->audio->nb_samples);
+    AVFrame *outsamples = ff_get_audio_buffer(inlink, insamples->nb_samples);
     int ret;
 
-    if (!outsamples)
+    if (!outsamples) {
+        av_frame_free(&insamples);
         return AVERROR(ENOMEM);
-    avfilter_copy_buffer_ref_props(outsamples, insamples);
+    }
+    av_frame_copy_props(outsamples, insamples);
 
     taps  = ((EarwaxContext *)inlink->dst->priv)->taps;
     out   = (int16_t *)outsamples->data[0];
@@ -131,14 +131,14 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
     out   = scalarproduct(taps, taps + NUMTAPS, out);
 
     // process current input
-    endin = in + insamples->audio->nb_samples * 2 - NUMTAPS;
+    endin = in + insamples->nb_samples * 2 - NUMTAPS;
     scalarproduct(in, endin, out);
 
     // save part of input for next round
     memcpy(taps, endin, NUMTAPS * sizeof(*taps));
 
     ret = ff_filter_frame(outlink, outsamples);
-    avfilter_unref_buffer(insamples);
+    av_frame_free(&insamples);
     return ret;
 }
 
@@ -147,7 +147,6 @@ static const AVFilterPad earwax_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index 864663b616bf0cd80e2d86ee08c59464bb3d4138..d700f20156a3e3f6c4d0eabe06d5954ecbeb0994 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -56,24 +56,14 @@ typedef struct JoinContext {
     /**
      * Temporary storage for input frames, until we get one on each input.
      */
-    AVFilterBufferRef **input_frames;
+    AVFrame **input_frames;
 
     /**
-     *  Temporary storage for data pointers, for assembling the output buffer.
+     *  Temporary storage for buffer references, for assembling the output frame.
      */
-    uint8_t **data;
+    AVBufferRef **buffers;
 } JoinContext;
 
-/**
- * To avoid copying the data from input buffers, this filter creates
- * a custom output buffer that stores references to all inputs and
- * unrefs them on free.
- */
-typedef struct JoinBufferPriv {
-    AVFilterBufferRef **in_buffers;
-    int              nb_in_buffers;
-} JoinBufferPriv;
-
 #define OFFSET(x) offsetof(JoinContext, x)
 #define A AV_OPT_FLAG_AUDIO_PARAM
 #define F AV_OPT_FLAG_FILTERING_PARAM
@@ -94,7 +84,7 @@ static const AVClass join_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     AVFilterContext *ctx = link->dst;
     JoinContext       *s = ctx->priv;
@@ -105,7 +95,7 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf)
             break;
     av_assert0(i < ctx->nb_inputs);
     av_assert0(!s->input_frames[i]);
-    s->input_frames[i] = buf;
+    s->input_frames[i] = frame;
 
     return 0;
 }
@@ -207,9 +197,9 @@ static int join_init(AVFilterContext *ctx, const char *args)
 
     s->nb_channels  = av_get_channel_layout_nb_channels(s->channel_layout);
     s->channels     = av_mallocz(sizeof(*s->channels) * s->nb_channels);
-    s->data         = av_mallocz(sizeof(*s->data)     * s->nb_channels);
+    s->buffers      = av_mallocz(sizeof(*s->buffers)  * s->nb_channels);
     s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs);
-    if (!s->channels || !s->data || !s->input_frames) {
+    if (!s->channels || !s->buffers|| !s->input_frames) {
         ret = AVERROR(ENOMEM);
         goto fail;
     }
@@ -248,11 +238,11 @@ static void join_uninit(AVFilterContext *ctx)
 
     for (i = 0; i < ctx->nb_inputs; i++) {
         av_freep(&ctx->input_pads[i].name);
-        avfilter_unref_bufferp(&s->input_frames[i]);
+        av_frame_free(&s->input_frames[i]);
     }
 
     av_freep(&s->channels);
-    av_freep(&s->data);
+    av_freep(&s->buffers);
     av_freep(&s->input_frames);
 }
 
@@ -394,34 +384,14 @@ fail:
     return ret;
 }
 
-static void join_free_buffer(AVFilterBuffer *buf)
-{
-    JoinBufferPriv *priv = buf->priv;
-
-    if (priv) {
-        int i;
-
-        for (i = 0; i < priv->nb_in_buffers; i++)
-            avfilter_unref_bufferp(&priv->in_buffers[i]);
-
-        av_freep(&priv->in_buffers);
-        av_freep(&buf->priv);
-    }
-
-    if (buf->extended_data != buf->data)
-        av_freep(&buf->extended_data);
-    av_freep(&buf);
-}
-
 static int join_request_frame(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     JoinContext *s       = ctx->priv;
-    AVFilterBufferRef *buf;
-    JoinBufferPriv *priv;
+    AVFrame *frame;
     int linesize   = INT_MAX;
-    int perms      = ~0;
     int nb_samples = 0;
+    int nb_buffers = 0;
     int i, j, ret;
 
     /* get a frame on each input */
@@ -434,54 +404,95 @@ static int join_request_frame(AVFilterLink *outlink)
 
         /* request the same number of samples on all inputs */
         if (i == 0) {
-            nb_samples = s->input_frames[0]->audio->nb_samples;
+            nb_samples = s->input_frames[0]->nb_samples;
 
             for (j = 1; !i && j < ctx->nb_inputs; j++)
                 ctx->inputs[j]->request_samples = nb_samples;
         }
     }
 
+    /* setup the output frame */
+    frame = av_frame_alloc();
+    if (!frame)
+        return AVERROR(ENOMEM);
+    if (s->nb_channels > FF_ARRAY_ELEMS(frame->data)) {
+        frame->extended_data = av_mallocz(s->nb_channels *
+                                          sizeof(*frame->extended_data));
+        if (!frame->extended_data) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }
+
+    /* copy the data pointers */
     for (i = 0; i < s->nb_channels; i++) {
         ChannelMap *ch = &s->channels[i];
-        AVFilterBufferRef *cur_buf = s->input_frames[ch->input];
-
-        s->data[i] = cur_buf->extended_data[ch->in_channel_idx];
-        linesize   = FFMIN(linesize, cur_buf->linesize[0]);
-        perms     &= cur_buf->perms;
-    }
+        AVFrame *cur   = s->input_frames[ch->input];
+        AVBufferRef *buf;
 
-    av_assert0(nb_samples > 0);
-    buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms,
-                                                    nb_samples, outlink->format,
-                                                    outlink->channel_layout);
-    if (!buf)
-        return AVERROR(ENOMEM);
+        frame->extended_data[i] = cur->extended_data[ch->in_channel_idx];
+        linesize = FFMIN(linesize, cur->linesize[0]);
 
-    buf->buf->free = join_free_buffer;
-    buf->pts       = s->input_frames[0]->pts;
+        /* add the buffer where this plan is stored to the list if it's
+         * not already there */
+        buf = av_frame_get_plane_buffer(cur, ch->in_channel_idx);
+        if (!buf) {
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
+        for (j = 0; j < nb_buffers; j++)
+            if (s->buffers[j]->buffer == buf->buffer)
+                break;
+        if (j == i)
+            s->buffers[nb_buffers++] = buf;
+    }
 
-    if (!(priv = av_mallocz(sizeof(*priv))))
-        goto fail;
-    if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs)))
-        goto fail;
+    /* create references to the buffers we copied to output */
+    if (nb_buffers > FF_ARRAY_ELEMS(frame->buf)) {
+        frame->nb_extended_buf = nb_buffers - FF_ARRAY_ELEMS(frame->buf);
+        frame->extended_buf = av_mallocz(sizeof(*frame->extended_buf) *
+                                         frame->nb_extended_buf);
+        if (!frame->extended_buf) {
+            frame->nb_extended_buf = 0;
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }
+    for (i = 0; i < FFMIN(FF_ARRAY_ELEMS(frame->buf), nb_buffers); i++) {
+        frame->buf[i] = av_buffer_ref(s->buffers[i]);
+        if (!frame->buf[i]) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }
+    for (i = 0; i < frame->nb_extended_buf; i++) {
+        frame->extended_buf[i] = av_buffer_ref(s->buffers[i +
+                                               FF_ARRAY_ELEMS(frame->buf)]);
+        if (!frame->extended_buf[i]) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    }
 
-    for (i = 0; i < ctx->nb_inputs; i++)
-        priv->in_buffers[i] = s->input_frames[i];
-    priv->nb_in_buffers = ctx->nb_inputs;
-    buf->buf->priv      = priv;
+    frame->nb_samples     = nb_samples;
+    frame->channel_layout = outlink->channel_layout;
+    frame->sample_rate    = outlink->sample_rate;
+    frame->pts            = s->input_frames[0]->pts;
+    frame->linesize[0]    = linesize;
+    if (frame->data != frame->extended_data) {
+        memcpy(frame->data, frame->extended_data, sizeof(*frame->data) *
+               FFMIN(FF_ARRAY_ELEMS(frame->data), s->nb_channels));
+    }
 
-    ret = ff_filter_frame(outlink, buf);
+    ret = ff_filter_frame(outlink, frame);
 
     memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);
 
     return ret;
 
 fail:
-    avfilter_unref_buffer(buf);
-    if (priv)
-        av_freep(&priv->in_buffers);
-    av_freep(&priv);
-    return AVERROR(ENOMEM);
+    av_frame_free(&frame);
+    return ret;
 }
 
 static const AVFilterPad avfilter_af_join_outputs[] = {
diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
index 77ca5491672b821677365bd319df2354603c0af5..9a3c10c1dcbee0f7196fce1ebfea60b47a5f9ab5 100644
--- a/libavfilter/af_pan.c
+++ b/libavfilter/af_pan.c
@@ -353,21 +353,21 @@ static int config_props(AVFilterLink *link)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     int ret;
-    int n = insamples->audio->nb_samples;
+    int n = insamples->nb_samples;
     AVFilterLink *const outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outsamples = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n);
+    AVFrame *outsamples = ff_get_audio_buffer(outlink, n);
     PanContext *pan = inlink->dst->priv;
 
     swr_convert(pan->swr, outsamples->data, n, (void *)insamples->data, n);
-    avfilter_copy_buffer_ref_props(outsamples, insamples);
-    outsamples->audio->channel_layout = outlink->channel_layout;
-    outsamples->audio->channels       = outlink->channels;
+    av_frame_copy_props(outsamples, insamples);
+    outsamples->channel_layout = outlink->channel_layout;
+    outsamples->channels       = outlink->channels;
 
     ret = ff_filter_frame(outlink, outsamples);
-    avfilter_unref_buffer(insamples);
+    av_frame_free(&insamples);
     return ret;
 }
 
@@ -383,7 +383,6 @@ static const AVFilterPad pan_inputs[] = {
         .type         = AVMEDIA_TYPE_AUDIO,
         .config_props = config_props,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c
index 84ca8f5501b7b015e413a543f48972a69f25feea..f82a970bb3d30bb31be728e200bd76523337fcbb 100644
--- a/libavfilter/af_resample.c
+++ b/libavfilter/af_resample.c
@@ -174,7 +174,7 @@ static int request_frame(AVFilterLink *outlink)
 
     /* flush the lavr delay buffer */
     if (ret == AVERROR_EOF && s->avr) {
-        AVFilterBufferRef *buf;
+        AVFrame *frame;
         int nb_samples = av_rescale_rnd(avresample_get_delay(s->avr),
                                         outlink->sample_rate,
                                         ctx->inputs[0]->sample_rate,
@@ -183,25 +183,25 @@ static int request_frame(AVFilterLink *outlink)
         if (!nb_samples)
             return ret;
 
-        buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
-        if (!buf)
+        frame = ff_get_audio_buffer(outlink, nb_samples);
+        if (!frame)
             return AVERROR(ENOMEM);
 
-        ret = avresample_convert(s->avr, buf->extended_data,
-                                 buf->linesize[0], nb_samples,
+        ret = avresample_convert(s->avr, frame->extended_data,
+                                 frame->linesize[0], nb_samples,
                                  NULL, 0, 0);
         if (ret <= 0) {
-            avfilter_unref_buffer(buf);
+            av_frame_free(&frame);
             return (ret == 0) ? AVERROR_EOF : ret;
         }
 
-        buf->pts = s->next_pts;
-        return ff_filter_frame(outlink, buf);
+        frame->pts = s->next_pts;
+        return ff_filter_frame(outlink, frame);
     }
     return ret;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext  *ctx = inlink->dst;
     ResampleContext    *s = ctx->priv;
@@ -209,27 +209,26 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     int ret;
 
     if (s->avr) {
-        AVFilterBufferRef *buf_out;
+        AVFrame *out;
         int delay, nb_samples;
 
         /* maximum possible samples lavr can output */
         delay      = avresample_get_delay(s->avr);
-        nb_samples = av_rescale_rnd(buf->audio->nb_samples + delay,
+        nb_samples = av_rescale_rnd(in->nb_samples + delay,
                                     outlink->sample_rate, inlink->sample_rate,
                                     AV_ROUND_UP);
 
-        buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
-        if (!buf_out) {
+        out = ff_get_audio_buffer(outlink, nb_samples);
+        if (!out) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
 
-        ret     = avresample_convert(s->avr, buf_out->extended_data,
-                                     buf_out->linesize[0], nb_samples,
-                                     buf->extended_data, buf->linesize[0],
-                                     buf->audio->nb_samples);
+        ret = avresample_convert(s->avr, out->extended_data, out->linesize[0],
+                                 nb_samples, in->extended_data, in->linesize[0],
+                                 in->nb_samples);
         if (ret <= 0) {
-            avfilter_unref_buffer(buf_out);
+            av_frame_free(&out);
             if (ret < 0)
                 goto fail;
         }
@@ -237,36 +236,36 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
         av_assert0(!avresample_available(s->avr));
 
         if (s->next_pts == AV_NOPTS_VALUE) {
-            if (buf->pts == AV_NOPTS_VALUE) {
+            if (in->pts == AV_NOPTS_VALUE) {
                 av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, "
                        "assuming 0.\n");
                 s->next_pts = 0;
             } else
-                s->next_pts = av_rescale_q(buf->pts, inlink->time_base,
+                s->next_pts = av_rescale_q(in->pts, inlink->time_base,
                                            outlink->time_base);
         }
 
         if (ret > 0) {
-            buf_out->audio->nb_samples = ret;
-            if (buf->pts != AV_NOPTS_VALUE) {
-                buf_out->pts = av_rescale_q(buf->pts, inlink->time_base,
+            out->nb_samples = ret;
+            if (in->pts != AV_NOPTS_VALUE) {
+                out->pts = av_rescale_q(in->pts, inlink->time_base,
                                             outlink->time_base) -
                                av_rescale(delay, outlink->sample_rate,
                                           inlink->sample_rate);
             } else
-                buf_out->pts = s->next_pts;
+                out->pts = s->next_pts;
 
-            s->next_pts = buf_out->pts + buf_out->audio->nb_samples;
+            s->next_pts = out->pts + out->nb_samples;
 
-            ret = ff_filter_frame(outlink, buf_out);
+            ret = ff_filter_frame(outlink, out);
             s->got_output = 1;
         }
 
 fail:
-        avfilter_unref_buffer(buf);
+        av_frame_free(&in);
     } else {
-        buf->format = outlink->format;
-        ret = ff_filter_frame(outlink, buf);
+        in->format = outlink->format;
+        ret = ff_filter_frame(outlink, in);
         s->got_output = 1;
     }
 
@@ -278,7 +277,6 @@ static const AVFilterPad avfilter_af_resample_inputs[] = {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = filter_frame,
-        .min_perms      = AV_PERM_READ
     },
     { NULL }
 };
diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c
index 8a6017613777cc9f3cb10c947003a1823e291217..dbd9f5ffd76698ee8b9ef017f7ed92dda633c630 100644
--- a/libavfilter/af_silencedetect.c
+++ b/libavfilter/af_silencedetect.c
@@ -70,20 +70,20 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static char *get_metadata_val(AVFilterBufferRef *insamples, const char *key)
+static char *get_metadata_val(AVFrame *insamples, const char *key)
 {
     AVDictionaryEntry *e = av_dict_get(insamples->metadata, key, NULL, 0);
     return e && e->value ? e->value : NULL;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     int i;
     SilenceDetectContext *silence = inlink->dst->priv;
     const int nb_channels           = av_get_channel_layout_nb_channels(inlink->channel_layout);
     const int srate                 = inlink->sample_rate;
-    const int nb_samples            = insamples->audio->nb_samples * nb_channels;
-    const int64_t nb_samples_notify = srate * silence->duration    * nb_channels;
+    const int nb_samples            = insamples->nb_samples     * nb_channels;
+    const int64_t nb_samples_notify = srate * silence->duration * nb_channels;
 
     // scale number of null samples to the new sample rate
     if (silence->last_sample_rate && silence->last_sample_rate != srate)
diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
index 5ffa1fea4f2d778621fba1c9e32c7082e5c86253..5bdd831315efccab6bfba9fcdd2c1bac033d2271 100644
--- a/libavfilter/af_volume.c
+++ b/libavfilter/af_volume.c
@@ -226,21 +226,21 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     VolumeContext *vol    = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    int nb_samples        = buf->audio->nb_samples;
-    AVFilterBufferRef *out_buf;
+    int nb_samples        = buf->nb_samples;
+    AVFrame *out_buf;
 
     if (vol->volume == 1.0 || vol->volume_i == 256)
         return ff_filter_frame(outlink, buf);
 
     /* do volume scaling in-place if input buffer is writable */
-    if (buf->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(buf)) {
         out_buf = buf;
     } else {
-        out_buf = ff_get_audio_buffer(inlink, AV_PERM_WRITE, nb_samples);
+        out_buf = ff_get_audio_buffer(inlink, nb_samples);
         if (!out_buf)
             return AVERROR(ENOMEM);
         out_buf->pts = buf->pts;
@@ -276,7 +276,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     }
 
     if (buf != out_buf)
-        avfilter_unref_buffer(buf);
+        av_frame_free(&buf);
 
     return ff_filter_frame(outlink, out_buf);
 }
diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c
index 39265c0674f45bfea6c247e5c51a4b5c8d4bbe50..79d992e8d3cf1949478f0adad8b415d35fcd9a2c 100644
--- a/libavfilter/af_volumedetect.c
+++ b/libavfilter/af_volumedetect.c
@@ -49,12 +49,12 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *samples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *samples)
 {
     AVFilterContext *ctx = inlink->dst;
     VolDetectContext *vd = ctx->priv;
-    int64_t layout  = samples->audio->channel_layout;
-    int nb_samples  = samples->audio->nb_samples;
+    int64_t layout  = samples->channel_layout;
+    int nb_samples  = samples->nb_samples;
     int nb_channels = av_get_channel_layout_nb_channels(layout);
     int nb_planes   = nb_channels;
     int plane, i;
@@ -137,7 +137,6 @@ static const AVFilterPad volumedetect_inputs[] = {
         .type             = AVMEDIA_TYPE_AUDIO,
         .get_audio_buffer = ff_null_get_audio_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 8a3f126c729fa722266b0ea86d33ba5594d2e946..141a9a7aaae53dce05e1719dcf8a4bcd9cf484d9 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -193,8 +193,8 @@ void avfilter_register_all(void)
      * unconditionally */
     REGISTER_FILTER_UNCONDITIONAL(asrc_abuffer);
     REGISTER_FILTER_UNCONDITIONAL(vsrc_buffer);
-    REGISTER_FILTER_UNCONDITIONAL(asink_abuffer);
-    REGISTER_FILTER_UNCONDITIONAL(vsink_buffer);
+    //REGISTER_FILTER_UNCONDITIONAL(asink_abuffer);
+    //REGISTER_FILTER_UNCONDITIONAL(vsink_buffer);
     REGISTER_FILTER_UNCONDITIONAL(af_afifo);
     REGISTER_FILTER_UNCONDITIONAL(vf_fifo);
 }
diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c
index 5a324fccf08b06bccfcb351514cb157cb77154ef..8015da2ba19a521334910c4546d87e3681d81163 100644
--- a/libavfilter/asink_anullsink.c
+++ b/libavfilter/asink_anullsink.c
@@ -22,9 +22,9 @@
 #include "avfilter.h"
 #include "internal.h"
 
-static int null_filter_frame(AVFilterLink *link, AVFilterBufferRef *samplesref)
+static int null_filter_frame(AVFilterLink *link, AVFrame *frame)
 {
-    avfilter_unref_bufferp(&samplesref);
+    av_frame_free(&frame);
     return 0;
 }
 
diff --git a/libavfilter/asrc_aevalsrc.c b/libavfilter/asrc_aevalsrc.c
index 2e5fa98fd75df02d43a842cb31a8e20afc92f327..70908e66a8583298a9a408594e0980cb274aa108 100644
--- a/libavfilter/asrc_aevalsrc.c
+++ b/libavfilter/asrc_aevalsrc.c
@@ -212,14 +212,14 @@ static int query_formats(AVFilterContext *ctx)
 static int request_frame(AVFilterLink *outlink)
 {
     EvalContext *eval = outlink->src->priv;
-    AVFilterBufferRef *samplesref;
+    AVFrame *samplesref;
     int i, j;
     double t = eval->n * (double)1/eval->sample_rate;
 
     if (eval->duration >= 0 && t >= eval->duration)
         return AVERROR_EOF;
 
-    samplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, eval->nb_samples);
+    samplesref = ff_get_audio_buffer(outlink, eval->nb_samples);
 
     /* evaluate expression for each single sample and for each channel */
     for (i = 0; i < eval->nb_samples; i++, eval->n++) {
@@ -233,8 +233,7 @@ static int request_frame(AVFilterLink *outlink)
     }
 
     samplesref->pts = eval->pts;
-    samplesref->pos = -1;
-    samplesref->audio->sample_rate = eval->sample_rate;
+    samplesref->sample_rate = eval->sample_rate;
     eval->pts += eval->nb_samples;
 
     ff_filter_frame(outlink, samplesref);
diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c
index 43e9a7c9abad6e055d4d1afe5d02e297f76294db..e606ad9e0acc26d6867c115ea676af48f0e01c19 100644
--- a/libavfilter/asrc_anullsrc.c
+++ b/libavfilter/asrc_anullsrc.c
@@ -102,17 +102,15 @@ static int config_props(AVFilterLink *outlink)
 static int request_frame(AVFilterLink *outlink)
 {
     ANullContext *null = outlink->src->priv;
-    AVFilterBufferRef *samplesref;
+    AVFrame *samplesref;
 
-    samplesref =
-        ff_get_audio_buffer(outlink, AV_PERM_WRITE, null->nb_samples);
+    samplesref = ff_get_audio_buffer(outlink, null->nb_samples);
     samplesref->pts = null->pts;
-    samplesref->pos = -1;
-    samplesref->audio->channel_layout = null->channel_layout;
-    samplesref->audio->sample_rate = outlink->sample_rate;
+    samplesref->channel_layout = null->channel_layout;
+    samplesref->sample_rate = outlink->sample_rate;
 
-    ff_filter_frame(outlink, avfilter_ref_buffer(samplesref, ~0));
-    avfilter_unref_buffer(samplesref);
+    ff_filter_frame(outlink, av_frame_clone(samplesref));
+    av_frame_free(&samplesref);
 
     null->pts += null->nb_samples;
     return 0;
diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c
index 04901da3960b8743b5eb037c7db9448b8c9b092c..c13eb8b27166fe90171052d576d64fecb344edeb 100644
--- a/libavfilter/asrc_flite.c
+++ b/libavfilter/asrc_flite.c
@@ -245,22 +245,22 @@ static int config_props(AVFilterLink *outlink)
 
 static int request_frame(AVFilterLink *outlink)
 {
-    AVFilterBufferRef *samplesref;
+    AVFrame *samplesref;
     FliteContext *flite = outlink->src->priv;
     int nb_samples = FFMIN(flite->wave_nb_samples, flite->frame_nb_samples);
 
     if (!nb_samples)
         return AVERROR_EOF;
 
-    samplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples);
+    samplesref = ff_get_audio_buffer(outlink, nb_samples);
     if (!samplesref)
         return AVERROR(ENOMEM);
 
     memcpy(samplesref->data[0], flite->wave_samples,
            nb_samples * flite->wave->num_channels * 2);
     samplesref->pts = flite->pts;
-    samplesref->pos = -1;
-    samplesref->audio->sample_rate = flite->wave->sample_rate;
+    av_frame_set_pkt_pos(samplesref, -1);
+    av_frame_set_sample_rate(samplesref, flite->wave->sample_rate);
     flite->pts += nb_samples;
     flite->wave_samples += nb_samples * flite->wave->num_channels;
     flite->wave_nb_samples -= nb_samples;
diff --git a/libavfilter/audio.c b/libavfilter/audio.c
index c72979d4345b1c5c2b473ea2bd334c74daf4d474..b5a9f789f6f6252cdce9f0970139eef86bdf815c 100644
--- a/libavfilter/audio.c
+++ b/libavfilter/audio.c
@@ -22,6 +22,7 @@
 #include "libavutil/avassert.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
+#include "libavcodec/avcodec.h"
 
 #include "audio.h"
 #include "avfilter.h"
@@ -32,69 +33,70 @@ int avfilter_ref_get_channels(AVFilterBufferRef *ref)
     return ref->audio ? ref->audio->channels : 0;
 }
 
-AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms,
-                                            int nb_samples)
+AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples)
 {
-    return ff_get_audio_buffer(link->dst->outputs[0], perms, nb_samples);
+    return ff_get_audio_buffer(link->dst->outputs[0], nb_samples);
 }
 
-AVFilterBufferRef *ff_default_get_audio_buffer(AVFilterLink *link, int perms,
-                                               int nb_samples)
+AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples)
 {
-    AVFilterBufferRef *samplesref = NULL;
-    uint8_t **data;
-    int planar      = av_sample_fmt_is_planar(link->format);
-    int nb_channels = link->channels;
-    int planes      = planar ? nb_channels : 1;
-    int linesize;
-    int full_perms = AV_PERM_READ | AV_PERM_WRITE | AV_PERM_PRESERVE |
-                     AV_PERM_REUSE | AV_PERM_REUSE2 | AV_PERM_ALIGN;
-
-    av_assert1(!(perms & ~(full_perms | AV_PERM_NEG_LINESIZES)));
-
-    if (!(data = av_mallocz(sizeof(*data) * planes)))
+    AVFrame *frame = av_frame_alloc();
+    int channels = link->channels;
+    int buf_size, ret;
+
+    av_assert0(channels == av_get_channel_layout_nb_channels(link->channel_layout) || !av_get_channel_layout_nb_channels(link->channel_layout));
+
+    if (!frame)
+        return NULL;
+
+    buf_size = av_samples_get_buffer_size(NULL, channels, nb_samples,
+                                          link->format, 0);
+    if (buf_size < 0)
         goto fail;
 
-    if (av_samples_alloc(data, &linesize, nb_channels, nb_samples, link->format, 0) < 0)
+    frame->buf[0] = av_buffer_alloc(buf_size);
+    if (!frame->buf[0])
         goto fail;
 
-    samplesref = avfilter_get_audio_buffer_ref_from_arrays_channels(
-        data, linesize, full_perms, nb_samples, link->format,
-        link->channels, link->channel_layout);
-    if (!samplesref)
+    frame->nb_samples = nb_samples;
+    ret = avcodec_fill_audio_frame(frame, channels, link->format,
+                                   frame->buf[0]->data, buf_size, 0);
+    if (ret < 0)
         goto fail;
 
-    samplesref->audio->sample_rate = link->sample_rate;
+    av_samples_set_silence(frame->extended_data, 0, nb_samples, channels,
+                           link->format);
+
+    frame->nb_samples     = nb_samples;
+    frame->format         = link->format;
+    frame->channels       = link->channels;
+    frame->channel_layout = link->channel_layout;
+    frame->sample_rate    = link->sample_rate;
 
-    av_freep(&data);
+    return frame;
 
 fail:
-    if (data)
-        av_freep(&data[0]);
-    av_freep(&data);
-    return samplesref;
+    av_buffer_unref(&frame->buf[0]);
+    av_frame_free(&frame);
+    return NULL;
 }
 
-AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms,
-                                       int nb_samples)
+AVFrame *ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
 {
-    AVFilterBufferRef *ret = NULL;
+    AVFrame *ret = NULL;
 
     if (link->dstpad->get_audio_buffer)
-        ret = link->dstpad->get_audio_buffer(link, perms, nb_samples);
+        ret = link->dstpad->get_audio_buffer(link, nb_samples);
 
     if (!ret)
-        ret = ff_default_get_audio_buffer(link, perms, nb_samples);
-
-    if (ret)
-        ret->type = AVMEDIA_TYPE_AUDIO;
+        ret = ff_default_get_audio_buffer(link, nb_samples);
 
     return ret;
 }
 
+#if FF_API_AVFILTERBUFFER
 AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays_channels(uint8_t **data,
-                                                                      int linesize,
-                                                                      int perms,
+                                                                      int linesize,int perms,
                                                                       int nb_samples,
                                                                       enum AVSampleFormat sample_fmt,
                                                                       int channels,
@@ -179,3 +181,4 @@ AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
                                                               nb_samples, sample_fmt,
                                                               channels, channel_layout);
 }
+#endif
diff --git a/libavfilter/audio.h b/libavfilter/audio.h
index 8fe4d8ee00d2a2887735617fa7188164fc8eaa64..3335c96ecacf5286ad267d4caee6763c125a7121 100644
--- a/libavfilter/audio.h
+++ b/libavfilter/audio.h
@@ -44,25 +44,21 @@ static const enum AVSampleFormat ff_planar_sample_fmts_array[] = {
 };
 
 /** default handler for get_audio_buffer() for audio inputs */
-AVFilterBufferRef *ff_default_get_audio_buffer(AVFilterLink *link, int perms,
-                                                     int nb_samples);
+AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples);
 
 /** get_audio_buffer() handler for filters which simply pass audio along */
-AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms,
-                                                  int nb_samples);
+AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples);
 
 /**
  * Request an audio samples buffer with a specific set of permissions.
  *
  * @param link           the output link to the filter from which the buffer will
  *                       be requested
- * @param perms          the required access permissions
  * @param nb_samples     the number of samples per channel
  * @return               A reference to the samples. This must be unreferenced with
  *                       avfilter_unref_buffer when you are finished with it.
  */
-AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms,
-                                             int nb_samples);
+AVFrame *ff_get_audio_buffer(AVFilterLink *link, int nb_samples);
 
 /**
  * Send a buffer of audio samples to the next filter.
diff --git a/libavfilter/avcodec.c b/libavfilter/avcodec.c
index dd3c886df01e87760c7b17d1c4297ee46d6fd6ba..7ec5881e076f6867691c2ff00ed2a6f275ad3cb6 100644
--- a/libavfilter/avcodec.c
+++ b/libavfilter/avcodec.c
@@ -27,52 +27,6 @@
 #include "libavutil/avassert.h"
 #include "libavutil/opt.h"
 
-int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src)
-{
-    dst->pts    = src->pts;
-    dst->pos    = av_frame_get_pkt_pos(src);
-    dst->format = src->format;
-
-    av_dict_free(&dst->metadata);
-    av_dict_copy(&dst->metadata, av_frame_get_metadata(src), 0);
-
-    switch (dst->type) {
-    case AVMEDIA_TYPE_VIDEO:
-        dst->video->w                   = src->width;
-        dst->video->h                   = src->height;
-        dst->video->sample_aspect_ratio = src->sample_aspect_ratio;
-        dst->video->interlaced          = src->interlaced_frame;
-        dst->video->top_field_first     = src->top_field_first;
-        dst->video->key_frame           = src->key_frame;
-        dst->video->pict_type           = src->pict_type;
-        av_freep(&dst->video->qp_table);
-        dst->video->qp_table_linesize = 0;
-        if (src->qscale_table) {
-            int qsize = src->qstride ? src->qstride * ((src->height+15)/16) : (src->width+15)/16;
-            dst->video->qp_table = av_malloc(qsize);
-            if (!dst->video->qp_table)
-                return AVERROR(ENOMEM);
-            dst->video->qp_table_linesize = src->qstride;
-            dst->video->qp_table_size     = qsize;
-            memcpy(dst->video->qp_table, src->qscale_table, qsize);
-        }
-        break;
-    case AVMEDIA_TYPE_AUDIO:
-        dst->audio->sample_rate         = src->sample_rate;
-        dst->audio->channel_layout      = src->channel_layout;
-        dst->audio->channels            = src->channels;
-        if(src->channels < av_get_channel_layout_nb_channels(src->channel_layout)) {
-            av_log(NULL, AV_LOG_ERROR, "libavfilter does not support this channel layout\n");
-            return AVERROR(EINVAL);
-        }
-        break;
-    default:
-        return AVERROR(EINVAL);
-    }
-
-    return 0;
-}
-
 AVFilterBufferRef *avfilter_get_video_buffer_ref_from_frame(const AVFrame *frame,
                                                             int perms)
 {
diff --git a/libavfilter/avcodec.h b/libavfilter/avcodec.h
index 5f4209acecb0fbd82bc213db3f355f33701c34d7..a5952062a08e3784121cc8f714d247a398e4141a 100644
--- a/libavfilter/avcodec.h
+++ b/libavfilter/avcodec.h
@@ -31,22 +31,6 @@
 #include "libavcodec/avcodec.h" // AVFrame
 #include "avfilter.h"
 
-/**
- * Copy the frame properties of src to dst, without copying the actual
- * image data.
- *
- * @return 0 on success, a negative number on error.
- */
-int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src);
-
-/**
- * Copy the frame properties and data pointers of src to dst, without copying
- * the actual data.
- *
- * @return 0 on success, a negative number on error.
- */
-int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src);
-
 /**
  * Create and return a picref reference from the data and properties
  * contained in frame.
@@ -116,16 +100,4 @@ int avfilter_fill_frame_from_buffer_ref(AVFrame *frame,
                                         const AVFilterBufferRef *ref);
 #endif
 
-/**
- * Add frame data to buffer_src.
- *
- * @param buffer_src  pointer to a buffer source context
- * @param frame       a frame, or NULL to mark EOF
- * @param flags       a combination of AV_BUFFERSRC_FLAG_*
- * @return            >= 0 in case of success, a negative AVERROR code
- *                    in case of failure
- */
-int av_buffersrc_add_frame(AVFilterContext *buffer_src,
-                           const AVFrame *frame, int flags);
-
 #endif /* AVFILTER_AVCODEC_H */
diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c
index 079d55d564aca91129f7e282825840c257cf8117..634b9d7b5478b5950284c4dd4ce3f7adae15f5b3 100644
--- a/libavfilter/avf_concat.c
+++ b/libavfilter/avf_concat.c
@@ -157,7 +157,7 @@ static int config_output(AVFilterLink *outlink)
 }
 
 static void push_frame(AVFilterContext *ctx, unsigned in_no,
-                       AVFilterBufferRef *buf)
+                       AVFrame *buf)
 {
     ConcatContext *cat = ctx->priv;
     unsigned out_no = in_no % ctx->nb_outputs;
@@ -171,7 +171,7 @@ static void push_frame(AVFilterContext *ctx, unsigned in_no,
     /* add duration to input PTS */
     if (inlink->sample_rate)
         /* use number of audio samples */
-        in->pts += av_rescale_q(buf->audio->nb_samples,
+        in->pts += av_rescale_q(buf->nb_samples,
                                 (AVRational){ 1, inlink->sample_rate },
                                 outlink->time_base);
     else if (in->nb_frames >= 2)
@@ -182,7 +182,7 @@ static void push_frame(AVFilterContext *ctx, unsigned in_no,
     ff_filter_frame(outlink, buf);
 }
 
-static void process_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static void process_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx  = inlink->dst;
     ConcatContext *cat    = ctx->priv;
@@ -191,7 +191,7 @@ static void process_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     if (in_no < cat->cur_idx) {
         av_log(ctx, AV_LOG_ERROR, "Frame after EOF on input %s\n",
                ctx->input_pads[in_no].name);
-        avfilter_unref_buffer(buf);
+        av_frame_free(&buf);
     } else if (in_no >= cat->cur_idx + ctx->nb_outputs) {
         ff_bufqueue_add(ctx, &cat->in[in_no].queue, buf);
     } else {
@@ -199,27 +199,25 @@ static void process_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     }
 }
 
-static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms,
-                                           int w, int h)
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
 {
     AVFilterContext *ctx = inlink->dst;
     unsigned in_no = FF_INLINK_IDX(inlink);
     AVFilterLink *outlink = ctx->outputs[in_no % ctx->nb_outputs];
 
-    return ff_get_video_buffer(outlink, perms, w, h);
+    return ff_get_video_buffer(outlink, w, h);
 }
 
-static AVFilterBufferRef *get_audio_buffer(AVFilterLink *inlink, int perms,
-                                           int nb_samples)
+static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples)
 {
     AVFilterContext *ctx = inlink->dst;
     unsigned in_no = FF_INLINK_IDX(inlink);
     AVFilterLink *outlink = ctx->outputs[in_no % ctx->nb_outputs];
 
-    return ff_get_audio_buffer(outlink, perms, nb_samples);
+    return ff_get_audio_buffer(outlink, nb_samples);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     process_frame(inlink, buf);
     return 0; /* enhancement: handle error return */
@@ -256,7 +254,7 @@ static void send_silence(AVFilterContext *ctx, unsigned in_no, unsigned out_no)
     int64_t nb_samples, sent = 0;
     int frame_nb_samples;
     AVRational rate_tb = { 1, ctx->inputs[in_no]->sample_rate };
-    AVFilterBufferRef *buf;
+    AVFrame *buf;
     int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
 
     if (!rate_tb.den)
@@ -266,7 +264,7 @@ static void send_silence(AVFilterContext *ctx, unsigned in_no, unsigned out_no)
     frame_nb_samples = FFMAX(9600, rate_tb.den / 5); /* arbitrary */
     while (nb_samples) {
         frame_nb_samples = FFMIN(frame_nb_samples, nb_samples);
-        buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE, frame_nb_samples);
+        buf = ff_get_audio_buffer(outlink, frame_nb_samples);
         if (!buf)
             return;
         av_samples_set_silence(buf->extended_data, 0, frame_nb_samples,
@@ -360,7 +358,6 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
             for (str = 0; str < cat->nb_streams[type]; str++) {
                 AVFilterPad pad = {
                     .type             = type,
-                    .min_perms        = AV_PERM_READ | AV_PERM_PRESERVE,
                     .get_video_buffer = get_video_buffer,
                     .get_audio_buffer = get_audio_buffer,
                     .filter_frame     = filter_frame,
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 57b4a4d87e689f6e60d1a9757e43d514b1e9ab58..b1d78608fcc230b79e3daae50bed6493bb8e84e6 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -41,7 +41,7 @@ enum ColorMode    { CHANNEL, INTENSITY, NB_CLMODES };
 typedef struct {
     const AVClass *class;
     int w, h;
-    AVFilterBufferRef *outpicref;
+    AVFrame *outpicref;
     int req_fullfilled;
     int nb_display_channels;
     int channel_height;
@@ -122,7 +122,7 @@ static av_cold void uninit(AVFilterContext *ctx)
         av_freep(&showspectrum->rdft_data[i]);
     av_freep(&showspectrum->rdft_data);
     av_freep(&showspectrum->window_func_lut);
-    avfilter_unref_bufferp(&showspectrum->outpicref);
+    av_frame_free(&showspectrum->outpicref);
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -179,7 +179,7 @@ static int config_output(AVFilterLink *outlink)
     /* (re-)configuration if the video output changed (or first init) */
     if (rdft_bits != showspectrum->rdft_bits) {
         size_t rdft_size, rdft_listsize;
-        AVFilterBufferRef *outpicref;
+        AVFrame *outpicref;
 
         av_rdft_end(showspectrum->rdft);
         showspectrum->rdft = av_rdft_init(rdft_bits, DFT_R2C);
@@ -219,10 +219,9 @@ static int config_output(AVFilterLink *outlink)
             showspectrum->window_func_lut[i] = .5f * (1 - cos(2*M_PI*i / (win_size-1)));
 
         /* prepare the initial picref buffer (black frame) */
-        avfilter_unref_bufferp(&showspectrum->outpicref);
+        av_frame_free(&showspectrum->outpicref);
         showspectrum->outpicref = outpicref =
-            ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_PRESERVE|AV_PERM_REUSE2,
-                                outlink->w, outlink->h);
+            ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!outpicref)
             return AVERROR(ENOMEM);
         outlink->sample_aspect_ratio = (AVRational){1,1};
@@ -253,7 +252,7 @@ inline static void push_frame(AVFilterLink *outlink)
     showspectrum->filled = 0;
     showspectrum->req_fullfilled = 1;
 
-    ff_filter_frame(outlink, avfilter_ref_buffer(showspectrum->outpicref, ~AV_PERM_WRITE));
+    ff_filter_frame(outlink, av_frame_clone(showspectrum->outpicref));
 }
 
 static int request_frame(AVFilterLink *outlink)
@@ -272,12 +271,12 @@ static int request_frame(AVFilterLink *outlink)
     return ret;
 }
 
-static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insamples, int nb_samples)
+static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb_samples)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     ShowSpectrumContext *showspectrum = ctx->priv;
-    AVFilterBufferRef *outpicref = showspectrum->outpicref;
+    AVFrame *outpicref = showspectrum->outpicref;
 
     /* nb_freq contains the power of two superior or equal to the output image
      * height (or half the RDFT window size) */
@@ -462,11 +461,11 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFilterBufferRef *insampl
     return add_samples;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     AVFilterContext *ctx = inlink->dst;
     ShowSpectrumContext *showspectrum = ctx->priv;
-    int left_samples = insamples->audio->nb_samples;
+    int left_samples = insamples->nb_samples;
 
     showspectrum->consumed = 0;
     while (left_samples) {
@@ -475,7 +474,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
         left_samples -= added_samples;
     }
 
-    avfilter_unref_buffer(insamples);
+    av_frame_free(&insamples);
     return 0;
 }
 
@@ -484,7 +483,6 @@ static const AVFilterPad showspectrum_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
index 1b9d28d487ec73625d02f5bb55cc948bc6610e00..5d2c1ab83828abd192351cdae7a05c2411315ae8 100644
--- a/libavfilter/avf_showwaves.c
+++ b/libavfilter/avf_showwaves.c
@@ -44,7 +44,7 @@ typedef struct {
     char *rate_str;
     AVRational rate;
     int buf_idx;
-    AVFilterBufferRef *outpicref;
+    AVFrame *outpicref;
     int req_fullfilled;
     int n;
     int sample_count_mod;
@@ -89,7 +89,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     ShowWavesContext *showwaves = ctx->priv;
 
     av_freep(&showwaves->rate_str);
-    avfilter_unref_bufferp(&showwaves->outpicref);
+    av_frame_free(&showwaves->outpicref);
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -190,16 +190,16 @@ static int request_frame(AVFilterLink *outlink)
 
 #define MAX_INT16 ((1<<15) -1)
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     ShowWavesContext *showwaves = ctx->priv;
-    const int nb_samples = insamples->audio->nb_samples;
-    AVFilterBufferRef *outpicref = showwaves->outpicref;
+    const int nb_samples = insamples->nb_samples;
+    AVFrame *outpicref = showwaves->outpicref;
     int linesize = outpicref ? outpicref->linesize[0] : 0;
     int16_t *p = (int16_t *)insamples->data[0];
-    int nb_channels = av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
+    int nb_channels = av_get_channel_layout_nb_channels(insamples->channel_layout);
     int i, j, k, h, ret = 0;
     const int n = showwaves->n;
     const int x = 255 / (nb_channels * n); /* multiplication factor, pre-computed to avoid in-loop divisions */
@@ -208,12 +208,11 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
     for (i = 0; i < nb_samples; i++) {
         if (!showwaves->outpicref) {
             showwaves->outpicref = outpicref =
-                ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN,
-                                    outlink->w, outlink->h);
+                ff_get_video_buffer(outlink, outlink->w, outlink->h);
             if (!outpicref)
                 return AVERROR(ENOMEM);
-            outpicref->video->w = outlink->w;
-            outpicref->video->h = outlink->h;
+            outpicref->width  = outlink->w;
+            outpicref->height = outlink->h;
             outpicref->pts = insamples->pts +
                              av_rescale_q((p - (int16_t *)insamples->data[0]) / nb_channels,
                                           (AVRational){ 1, inlink->sample_rate },
@@ -251,7 +250,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
         outpicref = showwaves->outpicref;
     }
 
-    avfilter_unref_buffer(insamples);
+    av_frame_free(&insamples);
     return ret;
 }
 
@@ -260,7 +259,6 @@ static const AVFilterPad showwaves_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_AUDIO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index ffd1b4ea191d1fb618ab6ac9e325dca553309ef0..671734350ec56d16d15bf30d530f9a71e8af6117 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -34,43 +34,31 @@
 #include "internal.h"
 #include "audio.h"
 
-static int ff_filter_frame_framed(AVFilterLink *link, AVFilterBufferRef *frame);
+static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame);
 
-char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms)
-{
-    snprintf(buf, buf_size, "%s%s%s%s%s%s",
-             perms & AV_PERM_READ      ? "r" : "",
-             perms & AV_PERM_WRITE     ? "w" : "",
-             perms & AV_PERM_PRESERVE  ? "p" : "",
-             perms & AV_PERM_REUSE     ? "u" : "",
-             perms & AV_PERM_REUSE2    ? "U" : "",
-             perms & AV_PERM_NEG_LINESIZES ? "n" : "");
-    return buf;
-}
-
-void ff_tlog_ref(void *ctx, AVFilterBufferRef *ref, int end)
+void ff_tlog_ref(void *ctx, AVFrame *ref, int end)
 {
     av_unused char buf[16];
     ff_tlog(ctx,
-            "ref[%p buf:%p refcount:%d perms:%s data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64,
-            ref, ref->buf, ref->buf->refcount, ff_get_ref_perms_string(buf, sizeof(buf), ref->perms), ref->data[0],
+            "ref[%p buf:%p data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64,
+            ref, ref->buf, ref->data[0],
             ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
-            ref->pts, ref->pos);
+            ref->pts, av_frame_get_pkt_pos(ref));
 
-    if (ref->video) {
+    if (ref->width) {
         ff_tlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
-                ref->video->sample_aspect_ratio.num, ref->video->sample_aspect_ratio.den,
-                ref->video->w, ref->video->h,
-                !ref->video->interlaced     ? 'P' :         /* Progressive  */
-                ref->video->top_field_first ? 'T' : 'B',    /* Top / Bottom */
-                ref->video->key_frame,
-                av_get_picture_type_char(ref->video->pict_type));
+                ref->sample_aspect_ratio.num, ref->sample_aspect_ratio.den,
+                ref->width, ref->height,
+                !ref->interlaced_frame     ? 'P' :         /* Progressive  */
+                ref->top_field_first ? 'T' : 'B',    /* Top / Bottom */
+                ref->key_frame,
+                av_get_picture_type_char(ref->pict_type));
     }
-    if (ref->audio) {
+    if (ref->nb_samples) {
         ff_tlog(ctx, " cl:%"PRId64"d n:%d r:%d",
-                ref->audio->channel_layout,
-                ref->audio->nb_samples,
-                ref->audio->sample_rate);
+                ref->channel_layout,
+                ref->nb_samples,
+                ref->sample_rate);
     }
 
     ff_tlog(ctx, "]%s", end ? "\n" : "");
@@ -158,10 +146,7 @@ void avfilter_link_free(AVFilterLink **link)
     if (!*link)
         return;
 
-    if ((*link)->pool)
-        ff_free_pool((*link)->pool);
-
-    avfilter_unref_bufferp(&(*link)->partial_buf);
+    av_frame_free(&(*link)->partial_buf);
 
     av_freep(link);
 }
@@ -342,7 +327,7 @@ int ff_request_frame(AVFilterLink *link)
     else if (link->src->inputs[0])
         ret = ff_request_frame(link->src->inputs[0]);
     if (ret == AVERROR_EOF && link->partial_buf) {
-        AVFilterBufferRef *pbuf = link->partial_buf;
+        AVFrame *pbuf = link->partial_buf;
         link->partial_buf = NULL;
         ff_filter_frame_framed(link, pbuf);
         return 0;
@@ -633,76 +618,64 @@ 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)
+static int default_filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     return ff_filter_frame(link->dst->outputs[0], frame);
 }
 
-static int ff_filter_frame_framed(AVFilterLink *link, AVFilterBufferRef *frame)
+static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
 {
-    int (*filter_frame)(AVFilterLink *, AVFilterBufferRef *);
+    int (*filter_frame)(AVFilterLink *, AVFrame *);
     AVFilterPad *src = link->srcpad;
     AVFilterPad *dst = link->dstpad;
-    AVFilterBufferRef *out;
-    int perms, ret;
+    AVFrame *out;
+    int ret;
     AVFilterCommand *cmd= link->dst->command_queue;
     int64_t pts;
 
     if (link->closed) {
-        avfilter_unref_buffer(frame);
+        av_frame_free(&frame);
         return AVERROR_EOF;
     }
 
     if (!(filter_frame = dst->filter_frame))
         filter_frame = default_filter_frame;
 
-    av_assert1((frame->perms & src->min_perms) == src->min_perms);
-    frame->perms &= ~ src->rej_perms;
-    perms = frame->perms;
-
-    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);
+    /* copy the frame if needed */
+    if (dst->needs_writable && !av_frame_is_writable(frame)) {
+        av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n");
 
         /* Maybe use ff_copy_buffer_ref instead? */
         switch (link->type) {
         case AVMEDIA_TYPE_VIDEO:
-            out = ff_get_video_buffer(link, dst->min_perms,
-                                      link->w, link->h);
+            out = ff_get_video_buffer(link, link->w, link->h);
             break;
         case AVMEDIA_TYPE_AUDIO:
-            out = ff_get_audio_buffer(link, dst->min_perms,
-                                      frame->audio->nb_samples);
+            out = ff_get_audio_buffer(link, frame->nb_samples);
             break;
         default: return AVERROR(EINVAL);
         }
         if (!out) {
-            avfilter_unref_buffer(frame);
+            av_frame_free(&frame);
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(out, frame);
+        av_frame_copy_props(out, frame);
 
         switch (link->type) {
         case AVMEDIA_TYPE_VIDEO:
             av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize,
-                          frame->format, frame->video->w, frame->video->h);
+                          frame->format, frame->width, frame->height);
             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),
+                            0, 0, frame->nb_samples,
+                            av_get_channel_layout_nb_channels(frame->channel_layout),
                             frame->format);
             break;
         default: return AVERROR(EINVAL);
         }
 
-        avfilter_unref_buffer(frame);
+        av_frame_free(&frame);
     } else
         out = frame;
 
@@ -721,48 +694,47 @@ static int ff_filter_frame_framed(AVFilterLink *link, AVFilterBufferRef *frame)
     return ret;
 }
 
-static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFilterBufferRef *frame)
+static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
 {
-    int insamples = frame->audio->nb_samples, inpos = 0, nb_samples;
-    AVFilterBufferRef *pbuf = link->partial_buf;
-    int nb_channels = frame->audio->channels;
+    int insamples = frame->nb_samples, inpos = 0, nb_samples;
+    AVFrame *pbuf = link->partial_buf;
+    int nb_channels = frame->channels;
     int ret = 0;
 
     /* Handle framing (min_samples, max_samples) */
     while (insamples) {
         if (!pbuf) {
             AVRational samples_tb = { 1, link->sample_rate };
-            int perms = link->dstpad->min_perms | AV_PERM_WRITE;
-            pbuf = ff_get_audio_buffer(link, perms, link->partial_buf_size);
+            pbuf = ff_get_audio_buffer(link, link->partial_buf_size);
             if (!pbuf) {
                 av_log(link->dst, AV_LOG_WARNING,
                        "Samples dropped due to memory allocation failure.\n");
                 return 0;
             }
-            avfilter_copy_buffer_ref_props(pbuf, frame);
+            av_frame_copy_props(pbuf, frame);
             pbuf->pts = frame->pts +
                         av_rescale_q(inpos, samples_tb, link->time_base);
-            pbuf->audio->nb_samples = 0;
+            pbuf->nb_samples = 0;
         }
         nb_samples = FFMIN(insamples,
-                           link->partial_buf_size - pbuf->audio->nb_samples);
+                           link->partial_buf_size - pbuf->nb_samples);
         av_samples_copy(pbuf->extended_data, frame->extended_data,
-                        pbuf->audio->nb_samples, inpos,
+                        pbuf->nb_samples, inpos,
                         nb_samples, nb_channels, link->format);
         inpos                   += nb_samples;
         insamples               -= nb_samples;
-        pbuf->audio->nb_samples += nb_samples;
-        if (pbuf->audio->nb_samples >= link->min_samples) {
+        pbuf->nb_samples += nb_samples;
+        if (pbuf->nb_samples >= link->min_samples) {
             ret = ff_filter_frame_framed(link, pbuf);
             pbuf = NULL;
         }
     }
-    avfilter_unref_buffer(frame);
+    av_frame_free(&frame);
     link->partial_buf = pbuf;
     return ret;
 }
 
-int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1);
 
@@ -770,22 +742,22 @@ int ff_filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
     if (link->type == AVMEDIA_TYPE_VIDEO) {
         if (strcmp(link->dst->filter->name, "scale")) {
             av_assert1(frame->format                 == link->format);
-            av_assert1(frame->video->w               == link->w);
-            av_assert1(frame->video->h               == link->h);
+            av_assert1(frame->width               == link->w);
+            av_assert1(frame->height               == link->h);
         }
     } else {
         av_assert1(frame->format                == link->format);
-        av_assert1(frame->audio->channels       == link->channels);
-        av_assert1(frame->audio->channel_layout == link->channel_layout);
-        av_assert1(frame->audio->sample_rate    == link->sample_rate);
+        av_assert1(frame->channels              == link->channels);
+        av_assert1(frame->channel_layout        == link->channel_layout);
+        av_assert1(frame->sample_rate           == link->sample_rate);
     }
 
     /* Go directly to actual filtering if possible */
     if (link->type == AVMEDIA_TYPE_AUDIO &&
         link->min_samples &&
         (link->partial_buf ||
-         frame->audio->nb_samples < link->min_samples ||
-         frame->audio->nb_samples > link->max_samples)) {
+         frame->nb_samples < link->min_samples ||
+         frame->nb_samples > link->max_samples)) {
         return ff_filter_frame_needs_framing(link, frame);
     } else {
         return ff_filter_frame_framed(link, frame);
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 1c80167b3b315569d715795c77e8f6c5dde4540c..45ad6f9f58588ddb7ef2c6fa05bfd78c0ca6ce49 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -37,6 +37,7 @@
 
 #include "libavutil/avutil.h"
 #include "libavutil/dict.h"
+#include "libavutil/frame.h"
 #include "libavutil/log.h"
 #include "libavutil/samplefmt.h"
 #include "libavutil/pixfmt.h"
@@ -69,6 +70,7 @@ typedef struct AVFilterLink    AVFilterLink;
 typedef struct AVFilterPad     AVFilterPad;
 typedef struct AVFilterFormats AVFilterFormats;
 
+#if FF_API_AVFILTERBUFFER
 /**
  * A reference-counted buffer data type used by the filter system. Filters
  * should not store pointers to this structure directly, but instead use the
@@ -200,6 +202,7 @@ typedef struct AVFilterBufferRef {
 /**
  * Copy properties of src to dst, without copying the actual data
  */
+attribute_deprecated
 void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *src);
 
 /**
@@ -211,6 +214,7 @@ void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *s
  * @return      a new reference to the buffer with the same properties as the
  *              old, excluding any permissions denied by pmask
  */
+attribute_deprecated
 AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask);
 
 /**
@@ -222,6 +226,7 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask);
  * @note it is recommended to use avfilter_unref_bufferp() instead of this
  * function
  */
+attribute_deprecated
 void avfilter_unref_buffer(AVFilterBufferRef *ref);
 
 /**
@@ -231,11 +236,14 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref);
  *
  * @param ref pointer to the buffer reference
  */
+attribute_deprecated
 void avfilter_unref_bufferp(AVFilterBufferRef **ref);
+#endif
 
 /**
  * Get the number of channels of a buffer reference.
  */
+attribute_deprecated
 int avfilter_ref_get_channels(AVFilterBufferRef *ref);
 
 #if FF_API_AVFILTERPAD_PUBLIC
@@ -273,7 +281,7 @@ struct AVFilterPad {
      * link must have at least these permissions; this fact is checked by
      * asserts. It can be used to optimize buffer allocation.
      */
-    int min_perms;
+    attribute_deprecated int min_perms;
 
     /**
      * Input pads:
@@ -287,7 +295,7 @@ struct AVFilterPad {
      * Permissions which are automatically removed on outgoing buffers. It
      * can be used to optimize buffer allocation.
      */
-    int rej_perms;
+    attribute_deprecated int rej_perms;
 
     /**
      * @deprecated unused
@@ -300,7 +308,7 @@ struct AVFilterPad {
      *
      * Input video pads only.
      */
-    AVFilterBufferRef *(*get_video_buffer)(AVFilterLink *link, int perms, int w, int h);
+    AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);
 
     /**
      * Callback function to get an audio buffer. If NULL, the filter system will
@@ -308,8 +316,7 @@ struct AVFilterPad {
      *
      * Input audio pads only.
      */
-    AVFilterBufferRef *(*get_audio_buffer)(AVFilterLink *link, int perms,
-                                           int nb_samples);
+    AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
 
     /**
      * @deprecated unused
@@ -331,7 +338,7 @@ struct AVFilterPad {
      * must ensure that frame is properly unreferenced on error if it
      * hasn't been passed on to another filter.
      */
-    int (*filter_frame)(AVFilterLink *link, AVFilterBufferRef *frame);
+    int (*filter_frame)(AVFilterLink *link, AVFrame *frame);
 
     /**
      * Frame poll callback. This returns the number of immediately available
@@ -381,6 +388,8 @@ struct AVFilterPad {
      * input pads only.
      */
     int needs_fifo;
+
+    int needs_writable;
 };
 #endif
 
@@ -616,7 +625,7 @@ struct AVFilterLink {
     /**
      * Buffer partially filled with samples to achieve a fixed/minimum size.
      */
-    AVFilterBufferRef *partial_buf;
+    AVFrame *partial_buf;
 
     /**
      * Size of the partial buffer to allocate.
@@ -701,6 +710,7 @@ void avfilter_link_set_closed(AVFilterLink *link, int closed);
  */
 int avfilter_config_links(AVFilterContext *filter);
 
+#if FF_API_AVFILTERBUFFER
 /**
  * Create a buffer reference wrapped around an already allocated image
  * buffer.
@@ -712,6 +722,7 @@ int avfilter_config_links(AVFilterContext *filter);
  * @param h the height of the image specified by the data and linesize arrays
  * @param format the pixel format of the image specified by the data and linesize arrays
  */
+attribute_deprecated
 AVFilterBufferRef *
 avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int linesize[4], int perms,
                                           int w, int h, enum AVPixelFormat format);
@@ -730,6 +741,7 @@ avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int lin
  * @param sample_fmt     the format of each sample in the buffer to allocate
  * @param channel_layout the channel layout of the buffer
  */
+attribute_deprecated
 AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
                                                              int linesize,
                                                              int perms,
@@ -749,6 +761,7 @@ AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
  * @param channel_layout the channel layout of the buffer,
  *                       must be either 0 or consistent with channels
  */
+attribute_deprecated
 AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays_channels(uint8_t **data,
                                                                       int linesize,
                                                                       int perms,
@@ -757,6 +770,7 @@ AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays_channels(uint8_t **
                                                                       int channels,
                                                                       uint64_t channel_layout);
 
+#endif
 
 
 #define AVFILTER_CMD_FLAG_ONE   1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically
@@ -845,6 +859,26 @@ void avfilter_free(AVFilterContext *filter);
 int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
                            unsigned filt_srcpad_idx, unsigned filt_dstpad_idx);
 
+#if FF_API_AVFILTERBUFFER
+/**
+ * Copy the frame properties of src to dst, without copying the actual
+ * image data.
+ *
+ * @return 0 on success, a negative number on error.
+ */
+attribute_deprecated
+int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src);
+
+/**
+ * Copy the frame properties and data pointers of src to dst, without copying
+ * the actual data.
+ *
+ * @return 0 on success, a negative number on error.
+ */
+attribute_deprecated
+int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src);
+#endif
+
 /**
  * @}
  */
diff --git a/libavfilter/buffer.c b/libavfilter/buffer.c
index 9a3f131dd09f469f3cb2a24fa14bfce7131a7e5f..29fedc412604d59433d29df131d3202c91050f57 100644
--- a/libavfilter/buffer.c
+++ b/libavfilter/buffer.c
@@ -92,84 +92,13 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask)
     return ret;
 }
 
-void ff_free_pool(AVFilterPool *pool)
-{
-    int i;
-
-    av_assert0(pool->refcount > 0);
-
-    for (i = 0; i < POOL_SIZE; i++) {
-        if (pool->pic[i]) {
-            AVFilterBufferRef *picref = pool->pic[i];
-            /* free buffer: picrefs stored in the pool are not
-             * supposed to contain a free callback */
-            av_assert0(!picref->buf->refcount);
-            av_freep(&picref->buf->data[0]);
-            av_freep(&picref->buf);
-
-            av_freep(&picref->audio);
-            av_assert0(!picref->video || !picref->video->qp_table);
-            av_freep(&picref->video);
-            av_freep(&pool->pic[i]);
-            pool->count--;
-        }
-    }
-    pool->draining = 1;
-
-    if (!--pool->refcount) {
-        av_assert0(!pool->count);
-        av_free(pool);
-    }
-}
-
-static void store_in_pool(AVFilterBufferRef *ref)
-{
-    int i;
-    AVFilterPool *pool= ref->buf->priv;
-
-    av_assert0(ref->buf->data[0]);
-    av_assert0(pool->refcount>0);
-
-    if (ref->video)
-        av_freep(&ref->video->qp_table);
-
-    if (pool->count == POOL_SIZE) {
-        AVFilterBufferRef *ref1 = pool->pic[0];
-        av_freep(&ref1->video);
-        av_freep(&ref1->audio);
-        av_freep(&ref1->buf->data[0]);
-        av_freep(&ref1->buf);
-        av_free(ref1);
-        memmove(&pool->pic[0], &pool->pic[1], sizeof(void*)*(POOL_SIZE-1));
-        pool->count--;
-        pool->pic[POOL_SIZE-1] = NULL;
-    }
-
-    for (i = 0; i < POOL_SIZE; i++) {
-        if (!pool->pic[i]) {
-            pool->pic[i] = ref;
-            pool->count++;
-            break;
-        }
-    }
-    if (pool->draining) {
-        ff_free_pool(pool);
-    } else
-        --pool->refcount;
-}
-
 void avfilter_unref_buffer(AVFilterBufferRef *ref)
 {
     if (!ref)
         return;
     av_assert0(ref->buf->refcount > 0);
-    if (!(--ref->buf->refcount)) {
-        if (!ref->buf->free) {
-            store_in_pool(ref);
-            return;
-        }
+    if (!(--ref->buf->refcount))
         ref->buf->free(ref->buf);
-    }
     if (ref->extended_data != ref->data)
         av_freep(&ref->extended_data);
     if (ref->video)
@@ -186,6 +115,36 @@ void avfilter_unref_bufferp(AVFilterBufferRef **ref)
     *ref = NULL;
 }
 
+int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src)
+{
+    dst->pts    = src->pts;
+    dst->pos    = av_frame_get_pkt_pos(src);
+    dst->format = src->format;
+
+    av_dict_free(&dst->metadata);
+    av_dict_copy(&dst->metadata, av_frame_get_metadata(src), 0);
+
+    switch (dst->type) {
+    case AVMEDIA_TYPE_VIDEO:
+        dst->video->w                   = src->width;
+        dst->video->h                   = src->height;
+        dst->video->sample_aspect_ratio = src->sample_aspect_ratio;
+        dst->video->interlaced          = src->interlaced_frame;
+        dst->video->top_field_first     = src->top_field_first;
+        dst->video->key_frame           = src->key_frame;
+        dst->video->pict_type           = src->pict_type;
+        break;
+    case AVMEDIA_TYPE_AUDIO:
+        dst->audio->sample_rate         = src->sample_rate;
+        dst->audio->channel_layout      = src->channel_layout;
+        break;
+    default:
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
 void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *src)
 {
     // copy common properties
@@ -206,40 +165,3 @@ void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *s
     av_dict_free(&dst->metadata);
     av_dict_copy(&dst->metadata, src->metadata, 0);
 }
-
-AVFilterBufferRef *ff_copy_buffer_ref(AVFilterLink *outlink,
-                                      AVFilterBufferRef *ref)
-{
-    AVFilterBufferRef *buf;
-    int channels;
-
-    switch (outlink->type) {
-
-    case AVMEDIA_TYPE_VIDEO:
-        buf = ff_get_video_buffer(outlink, AV_PERM_WRITE,
-                                  ref->video->w, ref->video->h);
-        if(!buf)
-            return NULL;
-        av_image_copy(buf->data, buf->linesize,
-                      (void*)ref->data, ref->linesize,
-                      ref->format, ref->video->w, ref->video->h);
-        break;
-
-    case AVMEDIA_TYPE_AUDIO:
-        buf = ff_get_audio_buffer(outlink, AV_PERM_WRITE,
-                                        ref->audio->nb_samples);
-        if(!buf)
-            return NULL;
-        channels = ref->audio->channels;
-        av_samples_copy(buf->extended_data, ref->buf->extended_data,
-                        0, 0, ref->audio->nb_samples,
-                        channels,
-                        ref->format);
-        break;
-
-    default:
-        return NULL;
-    }
-    avfilter_copy_buffer_ref_props(buf, ref);
-    return buf;
-}
diff --git a/libavfilter/bufferqueue.h b/libavfilter/bufferqueue.h
index 34c4c0f08ba3d1aaa4c81dd39ab6b15eda107652..adbc0fd895338476d827deaa7136e88a88b88943 100644
--- a/libavfilter/bufferqueue.h
+++ b/libavfilter/bufferqueue.h
@@ -23,7 +23,7 @@
 #define AVFILTER_BUFFERQUEUE_H
 
 /**
- * FFBufQueue: simple AVFilterBufferRef queue API
+ * FFBufQueue: simple AVFrame queue API
  *
  * Note: this API is not thread-safe. Concurrent access to the same queue
  * must be protected by a mutex or any synchronization mechanism.
@@ -47,7 +47,7 @@
  * Structure holding the queue
  */
 struct FFBufQueue {
-    AVFilterBufferRef *queue[FF_BUFQUEUE_SIZE];
+    AVFrame *queue[FF_BUFQUEUE_SIZE];
     unsigned short head;
     unsigned short available; /**< number of available buffers */
 };
@@ -69,11 +69,11 @@ static inline int ff_bufqueue_is_full(struct FFBufQueue *queue)
  * (and unrefed) with a warning before adding the new buffer.
  */
 static inline void ff_bufqueue_add(void *log, struct FFBufQueue *queue,
-                                   AVFilterBufferRef *buf)
+                                   AVFrame *buf)
 {
     if (ff_bufqueue_is_full(queue)) {
         av_log(log, AV_LOG_WARNING, "Buffer queue overflow, dropping.\n");
-        avfilter_unref_buffer(BUCKET(--queue->available));
+        av_frame_free(&BUCKET(--queue->available));
     }
     BUCKET(queue->available++) = buf;
 }
@@ -84,8 +84,8 @@ static inline void ff_bufqueue_add(void *log, struct FFBufQueue *queue,
  * Buffer with index 0 is the first buffer in the queue.
  * Return NULL if the queue has not enough buffers.
  */
-static inline AVFilterBufferRef *ff_bufqueue_peek(struct FFBufQueue *queue,
-                                                  unsigned index)
+static inline AVFrame *ff_bufqueue_peek(struct FFBufQueue *queue,
+                                        unsigned index)
 {
     return index < queue->available ? BUCKET(index) : NULL;
 }
@@ -95,9 +95,9 @@ static inline AVFilterBufferRef *ff_bufqueue_peek(struct FFBufQueue *queue,
  *
  * Do not use on an empty queue.
  */
-static inline AVFilterBufferRef *ff_bufqueue_get(struct FFBufQueue *queue)
+static inline AVFrame *ff_bufqueue_get(struct FFBufQueue *queue)
 {
-    AVFilterBufferRef *ret = queue->queue[queue->head];
+    AVFrame *ret = queue->queue[queue->head];
     av_assert0(queue->available);
     queue->available--;
     queue->queue[queue->head] = NULL;
@@ -110,8 +110,10 @@ static inline AVFilterBufferRef *ff_bufqueue_get(struct FFBufQueue *queue)
  */
 static inline void ff_bufqueue_discard_all(struct FFBufQueue *queue)
 {
-    while (queue->available)
-        avfilter_unref_buffer(ff_bufqueue_get(queue));
+    while (queue->available) {
+        AVFrame *buf = ff_bufqueue_get(queue);
+        av_frame_free(&buf);
+    }
 }
 
 #undef BUCKET
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 282be30071fc03b286976f716c5cfe6ebe52c044..f68221644c2dadc184e734fae2558cc01d2ebe94 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -35,7 +35,7 @@
 #include "internal.h"
 
 typedef struct {
-    AVFilterBufferRef *cur_buf;  ///< last buffer delivered on the sink
+    AVFrame *cur_frame;          ///< last frame delivered on the sink
     AVAudioFifo  *audio_fifo;    ///< FIFO for audio samples
     int64_t next_pts;            ///< interpolating audio pts
 } BufferSinkContext;
@@ -48,59 +48,71 @@ static av_cold void uninit(AVFilterContext *ctx)
         av_audio_fifo_free(sink->audio_fifo);
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     BufferSinkContext *s = link->dst->priv;
 
-//     av_assert0(!s->cur_buf);
-    s->cur_buf    = buf;
+//     av_assert0(!s->cur_frame);
+    s->cur_frame = frame;
 
     return 0;
 }
 
+<<<<<<< HEAD
 int ff_buffersink_read_compat(AVFilterContext *ctx, AVFilterBufferRef **buf)
+||||||| merged common ancestors
+int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
+=======
+int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
+>>>>>>> 7e350379f87e7f74420b4813170fe808e2313911
 {
     BufferSinkContext *s    = ctx->priv;
     AVFilterLink      *link = ctx->inputs[0];
     int ret;
 
-    if (!buf)
-        return ff_poll_frame(ctx->inputs[0]);
-
     if ((ret = ff_request_frame(link)) < 0)
         return ret;
 
-    if (!s->cur_buf)
+    if (!s->cur_frame)
         return AVERROR(EINVAL);
 
-    *buf       = s->cur_buf;
-    s->cur_buf = NULL;
+    av_frame_move_ref(frame, s->cur_frame);
+    av_frame_free(&s->cur_frame);
 
     return 0;
 }
 
-static int read_from_fifo(AVFilterContext *ctx, AVFilterBufferRef **pbuf,
+static int read_from_fifo(AVFilterContext *ctx, AVFrame *frame,
                           int nb_samples)
 {
     BufferSinkContext *s = ctx->priv;
     AVFilterLink   *link = ctx->inputs[0];
-    AVFilterBufferRef *buf;
+    AVFrame *tmp;
 
-    if (!(buf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples)))
+    if (!(tmp = ff_get_audio_buffer(link, nb_samples)))
         return AVERROR(ENOMEM);
-    av_audio_fifo_read(s->audio_fifo, (void**)buf->extended_data, nb_samples);
+    av_audio_fifo_read(s->audio_fifo, (void**)tmp->extended_data, nb_samples);
 
-    buf->pts = s->next_pts;
+    tmp->pts = s->next_pts;
     s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate},
                                 link->time_base);
 
-    *pbuf = buf;
+    av_frame_move_ref(frame, tmp);
+    av_frame_free(&tmp);
+
     return 0;
 
 }
 
+<<<<<<< HEAD
 int ff_buffersink_read_samples_compat(AVFilterContext *ctx, AVFilterBufferRef **pbuf,
                                       int nb_samples)
+||||||| merged common ancestors
+int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **pbuf,
+                               int nb_samples)
+=======
+int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples)
+>>>>>>> 7e350379f87e7f74420b4813170fe808e2313911
 {
     BufferSinkContext *s = ctx->priv;
     AVFilterLink   *link = ctx->inputs[0];
@@ -113,38 +125,107 @@ int ff_buffersink_read_samples_compat(AVFilterContext *ctx, AVFilterBufferRef **
     }
 
     while (ret >= 0) {
-        AVFilterBufferRef *buf;
-
         if (av_audio_fifo_size(s->audio_fifo) >= nb_samples)
-            return read_from_fifo(ctx, pbuf, nb_samples);
+            return read_from_fifo(ctx, frame, nb_samples);
 
-        ret = av_buffersink_read(ctx, &buf);
+        ret = ff_request_frame(link);
         if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo))
-            return read_from_fifo(ctx, pbuf, av_audio_fifo_size(s->audio_fifo));
+            return read_from_fifo(ctx, frame, av_audio_fifo_size(s->audio_fifo));
         else if (ret < 0)
             return ret;
 
-        if (buf->pts != AV_NOPTS_VALUE) {
-            s->next_pts = buf->pts -
+        if (s->cur_frame->pts != AV_NOPTS_VALUE) {
+            s->next_pts = s->cur_frame->pts -
                           av_rescale_q(av_audio_fifo_size(s->audio_fifo),
                                        (AVRational){ 1, link->sample_rate },
                                        link->time_base);
         }
 
-        ret = av_audio_fifo_write(s->audio_fifo, (void**)buf->extended_data,
-                                  buf->audio->nb_samples);
-        avfilter_unref_buffer(buf);
+        ret = av_audio_fifo_write(s->audio_fifo, (void**)s->cur_frame->extended_data,
+                                  s->cur_frame->nb_samples);
+        av_frame_free(&s->cur_frame);
+    }
+
+    return ret;
+
+}
+
+#if FF_API_AVFILTERBUFFER
+static void compat_free_buffer(AVFilterBuffer *buf)
+{
+    AVFrame *frame = buf->priv;
+    av_frame_free(&frame);
+    av_free(buf);
+}
+
+static int compat_read(AVFilterContext *ctx, AVFilterBufferRef **pbuf, int nb_samples)
+{
+    AVFilterBufferRef *buf;
+    AVFrame *frame;
+    int ret;
+
+    if (!pbuf)
+        return ff_poll_frame(ctx->inputs[0]);
+
+    frame = av_frame_alloc();
+    if (!frame)
+        return AVERROR(ENOMEM);
+
+    if (!nb_samples)
+        ret = av_buffersink_get_frame(ctx, frame);
+    else
+        ret = av_buffersink_get_samples(ctx, frame, nb_samples);
+
+    if (ret < 0)
+        goto fail;
+
+    if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) {
+        buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize,
+                                                        AV_PERM_READ,
+                                                        frame->width, frame->height,
+                                                        frame->format);
+    } else {
+        buf = avfilter_get_audio_buffer_ref_from_arrays(frame->extended_data,
+                                                        frame->linesize[0], AV_PERM_READ,
+                                                        frame->nb_samples,
+                                                        frame->format,
+                                                        frame->channel_layout);
     }
+    if (!buf) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    avfilter_copy_frame_props(buf, frame);
+
+    buf->buf->priv = frame;
+    buf->buf->free = compat_free_buffer;
+
+    *pbuf = buf;
 
+    return 0;
+fail:
+    av_frame_free(&frame);
     return ret;
 }
 
+int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
+{
+    return compat_read(ctx, buf, 0);
+}
+
+int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
+                               int nb_samples)
+{
+    return compat_read(ctx, buf, nb_samples);
+}
+#endif
+
 static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
     {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
-        .min_perms   = AV_PERM_READ,
         .needs_fifo  = 1
     },
     { NULL }
@@ -169,7 +250,6 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
         .name           = "default",
         .type           = AVMEDIA_TYPE_AUDIO,
         .filter_frame   = filter_frame,
-        .min_perms      = AV_PERM_READ,
         .needs_fifo     = 1
     },
     { NULL }
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index 6f8ac5cdf10a8be2b40d1748df3e1de4db05d7c5..eca3c23896e17f82129a162b398ea5fcd6d1c549 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -26,6 +26,7 @@
 
 #include "avfilter.h"
 
+#if FF_API_AVFILTERBUFFER
 /**
  * Struct to use for initializing a buffersink context.
  */
@@ -94,6 +95,8 @@ void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size);
 int av_buffersink_get_buffer_ref(AVFilterContext *buffer_sink,
                                  AVFilterBufferRef **bufref, int flags);
 
+/* TODO */
+int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags);
 
 /**
  * Get the number of immediately available frames.
@@ -122,6 +125,7 @@ AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx);
  * @return >= 0 in case of success, a negative AVERROR code in case of
  *         failure.
  */
+attribute_deprecated
 int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf);
 
 /**
@@ -140,8 +144,38 @@ int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf);
  * @warning do not mix this function with av_buffersink_read(). Use only one or
  * the other with a single sink, not both.
  */
+attribute_deprecated
 int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
                                int nb_samples);
+#endif
+
+/**
+ * Get a frame with filtered data from sink and put it in frame.
+ *
+ * @param ctx pointer to a context of a buffersink or abuffersink AVFilter.
+ * @param frame pointer to an allocated frame that will be filled with data.
+ *              The data must be freed using av_frame_unref() / av_frame_free()
+ *
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ *         failure.
+ */
+int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
+
+/**
+ * Same as av_buffersink_get_frame(), but with the ability to specify the number
+ * of samples read. This function is less efficient than
+ * av_buffersink_get_frame(), because it copies the data around.
+ *
+ * @param ctx pointer to a context of the abuffersink AVFilter.
+ * @param frame pointer to an allocated frame that will be filled with data.
+ *              The data must be freed using av_frame_unref() / av_frame_free()
+ *              frame will contain exactly nb_samples audio samples, except at
+ *              the end of stream, when it can contain less than nb_samples.
+ *
+ * @warning do not mix this function with av_buffersink_get_frame(). Use only one or
+ * the other with a single sink, not both.
+ */
+int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
 
 /**
  * @}
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index d150357ffa3476313154004b8d98915914796d39..6c6689b4cae8a71e3583669dfc35c45f636386ec 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -26,6 +26,7 @@
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/fifo.h"
+#include "libavutil/frame.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/opt.h"
 #include "libavutil/samplefmt.h"
@@ -74,99 +75,193 @@ typedef struct {
         return AVERROR(EINVAL);\
     }
 
-int av_buffersrc_add_frame(AVFilterContext *buffer_src,
-                           const AVFrame *frame, int flags)
+int av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
 {
-    AVFilterBufferRef *picref;
-    int ret;
+    return av_buffersrc_add_frame(ctx, frame);
+}
+
+int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame)
+{
+    AVFrame *copy;
+    int ret = 0;
+    int64_t layout = frame->channel_layout;
 
-    if (!frame) /* NULL for EOF */
-        return av_buffersrc_add_ref(buffer_src, NULL, flags);
+    if (layout && av_get_channel_layout_nb_channels(layout) != av_frame_get_channels(frame)) {
+        av_log(0, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
+        return AVERROR(EINVAL);
+    }
 
-    picref = avfilter_get_buffer_ref_from_frame(buffer_src->outputs[0]->type,
-                                                frame, AV_PERM_WRITE);
-    if (!picref)
+    if (!(copy = av_frame_alloc()))
         return AVERROR(ENOMEM);
-    ret = av_buffersrc_add_ref(buffer_src, picref, flags);
-    picref->buf->data[0] = NULL;
-    avfilter_unref_buffer(picref);
-    return ret;
-}
+    ret = av_frame_ref(copy, frame);
+    if (ret >= 0)
+        ret = av_buffersrc_add_frame(ctx, copy);
 
-int av_buffersrc_write_frame(AVFilterContext *buffer_filter, const AVFrame *frame)
-{
-    return av_buffersrc_add_frame(buffer_filter, frame, 0);
+    av_frame_free(&copy);
+    return ret;
 }
 
-int av_buffersrc_add_ref(AVFilterContext *s, AVFilterBufferRef *buf, int flags)
+int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
 {
-    BufferSourceContext *c = s->priv;
-    AVFilterBufferRef *to_free = NULL;
+    BufferSourceContext *s = ctx->priv;
+    AVFrame *copy;
     int ret;
+    int64_t layout;
 
-    if (!buf) {
-        c->eof = 1;
+    if (!frame) {
+        s->eof = 1;
         return 0;
-    } else if (c->eof)
+    } else if (s->eof)
         return AVERROR(EINVAL);
 
-    if (!av_fifo_space(c->fifo) &&
-        (ret = av_fifo_realloc2(c->fifo, av_fifo_size(c->fifo) +
-                                         sizeof(buf))) < 0)
-        return ret;
+    switch (ctx->outputs[0]->type) {
+    case AVMEDIA_TYPE_VIDEO:
+        CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height,
+                                 frame->format);
+        break;
+    case AVMEDIA_TYPE_AUDIO:
+        CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout,
+                                 frame->format);
 
-    if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) {
-        switch (s->outputs[0]->type) {
-        case AVMEDIA_TYPE_VIDEO:
-            CHECK_VIDEO_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
-            break;
-        case AVMEDIA_TYPE_AUDIO:
-            if (!buf->audio->channel_layout)
-                buf->audio->channel_layout = c->channel_layout;
-            CHECK_AUDIO_PARAM_CHANGE(s, c, buf->audio->sample_rate, buf->audio->channel_layout,
-                                     buf->format);
-            break;
-        default:
+        layout = frame->channel_layout;
+        if (layout && av_get_channel_layout_nb_channels(layout) != av_frame_get_channels(frame)) {
+            av_log(0, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
             return AVERROR(EINVAL);
         }
+        break;
+    default:
+        return AVERROR(EINVAL);
     }
-    if (!(flags & AV_BUFFERSRC_FLAG_NO_COPY))
-        to_free = buf = ff_copy_buffer_ref(s->outputs[0], buf);
-    if(!buf)
-        return -1;
 
-    if ((ret = av_fifo_generic_write(c->fifo, &buf, sizeof(buf), NULL)) < 0) {
-        avfilter_unref_buffer(to_free);
+    if (!av_fifo_space(s->fifo) &&
+        (ret = av_fifo_realloc2(s->fifo, av_fifo_size(s->fifo) +
+                                         sizeof(copy))) < 0)
         return ret;
-    }
-    c->nb_failed_requests = 0;
-    if (c->warning_limit &&
-        av_fifo_size(c->fifo) / sizeof(buf) >= c->warning_limit) {
-        av_log(s, AV_LOG_WARNING,
-               "%d buffers queued in %s, something may be wrong.\n",
-               c->warning_limit,
-               (char *)av_x_if_null(s->name, s->filter->name));
-        c->warning_limit *= 10;
-    }
 
-    if ((flags & AV_BUFFERSRC_FLAG_PUSH))
-        if ((ret = s->output_pads[0].request_frame(s->outputs[0])) < 0)
-            return ret;
+    if (!(copy = av_frame_alloc()))
+        return AVERROR(ENOMEM);
+    av_frame_move_ref(copy, frame);
+
+    if ((ret = av_fifo_generic_write(s->fifo, &copy, sizeof(copy), NULL)) < 0) {
+        av_frame_move_ref(frame, copy);
+        av_frame_free(&copy);
+        return ret;
+    }
 
     return 0;
 }
 
-#ifdef FF_API_BUFFERSRC_BUFFER
-int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
+#if FF_API_AVFILTERBUFFER
+static void compat_free_buffer(void *opaque, uint8_t *data)
 {
-    return av_buffersrc_add_ref(s, buf, AV_BUFFERSRC_FLAG_NO_COPY);
+    AVFilterBufferRef *buf = opaque;
+    avfilter_unref_buffer(buf);
 }
-#endif
 
-unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src)
+static void compat_unref_buffer(void *opaque, uint8_t *data)
 {
-    return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests;
+    AVBufferRef *buf = opaque;
+    av_buffer_unref(&buf);
+}
+
+int av_buffersrc_add_ref(AVFilterContext *ctx, AVFilterBufferRef *buf,
+                         int flags)
+{
+    BufferSourceContext *s = ctx->priv;
+    AVFrame *frame = NULL;
+    AVBufferRef *dummy_buf = NULL;
+    int ret = 0, planes, i;
+
+    if (!buf) {
+        s->eof = 1;
+        return 0;
+    } else if (s->eof)
+        return AVERROR(EINVAL);
+
+    frame = av_frame_alloc();
+    if (!frame)
+        return AVERROR(ENOMEM);
+
+    dummy_buf = av_buffer_create(NULL, 0, compat_free_buffer, buf,
+                                 (buf->perms & AV_PERM_WRITE) ? 0 : AV_BUFFER_FLAG_READONLY);
+    if (!dummy_buf) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    if ((ret = avfilter_copy_buf_props(frame, buf)) < 0)
+        goto fail;
+
+#define WRAP_PLANE(ref_out, data, data_size)                            \
+do {                                                                    \
+    AVBufferRef *dummy_ref = av_buffer_ref(dummy_buf);                  \
+    if (!dummy_ref) {                                                   \
+        ret = AVERROR(ENOMEM);                                          \
+        goto fail;                                                      \
+    }                                                                   \
+    ref_out = av_buffer_create(data, data_size, compat_unref_buffer,    \
+                               dummy_ref, (buf->perms & AV_PERM_WRITE) ? 0 : AV_BUFFER_FLAG_READONLY);                           \
+    if (!ref_out) {                                                     \
+        av_frame_unref(frame);                                          \
+        ret = AVERROR(ENOMEM);                                          \
+        goto fail;                                                      \
+    }                                                                   \
+} while (0)
+
+    if (ctx->outputs[0]->type  == AVMEDIA_TYPE_VIDEO) {
+        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+
+        if (!desc) {
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
+        planes = (desc->flags & PIX_FMT_PLANAR) ? desc->nb_components : 1;
+
+        for (i = 0; i < planes; i++) {
+            int h_shift    = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
+            int plane_size = (frame->width >> h_shift) * frame->linesize[i];
+
+            WRAP_PLANE(frame->buf[i], frame->data[i], plane_size);
+        }
+    } else {
+        int planar = av_sample_fmt_is_planar(frame->format);
+        int channels = av_get_channel_layout_nb_channels(frame->channel_layout);
+
+        planes = planar ? channels : 1;
+
+        if (planes > FF_ARRAY_ELEMS(frame->buf)) {
+            frame->nb_extended_buf = planes - FF_ARRAY_ELEMS(frame->buf);
+            frame->extended_buf = av_mallocz(sizeof(*frame->extended_buf) *
+                                             frame->nb_extended_buf);
+            if (!frame->extended_buf) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+        }
+
+        for (i = 0; i < FFMIN(planes, FF_ARRAY_ELEMS(frame->buf)); i++)
+            WRAP_PLANE(frame->buf[i], frame->extended_data[i], frame->linesize[0]);
+
+        for (i = 0; i < planes - FF_ARRAY_ELEMS(frame->buf); i++)
+            WRAP_PLANE(frame->extended_buf[i],
+                       frame->extended_data[i + FF_ARRAY_ELEMS(frame->buf)],
+                       frame->linesize[0]);
+    }
+
+    ret = av_buffersrc_add_frame_flags(ctx, frame, flags);
+
+fail:
+    av_buffer_unref(&dummy_buf);
+    av_frame_free(&frame);
+
+    return ret;
+}
+
+int av_buffersrc_buffer(AVFilterContext *ctx, AVFilterBufferRef *buf)
+{
+    return av_buffersrc_add_ref(ctx, buf, 0);
 }
+#endif
 
 #define OFFSET(x) offsetof(BufferSourceContext, x)
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
@@ -186,7 +281,7 @@ AVFILTER_DEFINE_CLASS(buffer);
 static av_cold int init_video(AVFilterContext *ctx, const char *args)
 {
     BufferSourceContext *c = ctx->priv;
-    char pix_fmt_str[128], sws_param[256] = "", *colon, *equal;
+    char pix_fmt_str[128], *colon, *equal;
     int ret, n = 0;
 
     c->class = &buffer_class;
@@ -195,6 +290,7 @@ static av_cold int init_video(AVFilterContext *ctx, const char *args)
         av_log(ctx, AV_LOG_ERROR, "Arguments required\n");
         return AVERROR(EINVAL);
     }
+
     colon = strchr(args, ':');
     equal = strchr(args, '=');
     if (equal && (!colon || equal < colon)) {
@@ -203,28 +299,25 @@ static av_cold int init_video(AVFilterContext *ctx, const char *args)
         if (ret < 0)
             goto fail;
     } else {
-    if ((n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d:%255c", &c->w, &c->h, pix_fmt_str,
+    if (!args ||
+        (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
                     &c->time_base.num, &c->time_base.den,
-                    &c->pixel_aspect.num, &c->pixel_aspect.den, sws_param)) < 7) {
-        av_log(ctx, AV_LOG_ERROR, "Expected at least 7 arguments, but only %d found in '%s'\n", n, args);
-        ret = AVERROR(EINVAL);
-        goto fail;
+                    &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) {
+        av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
+        return AVERROR(EINVAL);
     }
-    av_log(ctx, AV_LOG_WARNING, "Flat options syntax is deprecated, use key=value pairs\n");
-
-    if ((ret = ff_parse_pixel_format(&c->pix_fmt, pix_fmt_str, ctx)) < 0)
-        goto fail;
-    c->sws_param = av_strdup(sws_param);
-    if (!c->sws_param) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
+    if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == AV_PIX_FMT_NONE) {
+        char *tail;
+        c->pix_fmt = strtol(pix_fmt_str, &tail, 10);
+        if (*tail || c->pix_fmt < 0 || c->pix_fmt >= AV_PIX_FMT_NB) {
+            av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str);
+            return AVERROR(EINVAL);
+        }
     }
     }
 
-    if (!(c->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
-    }
+    if (!(c->fifo = av_fifo_alloc(sizeof(AVFrame*))))
+        return AVERROR(ENOMEM);
 
     av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d sws_param:%s\n",
            c->w, c->h, av_get_pix_fmt_name(c->pix_fmt),
@@ -238,6 +331,11 @@ fail:
     return ret;
 }
 
+unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src)
+{
+    return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests;
+}
+
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM
 static const AVOption abuffer_options[] = {
     { "time_base",      NULL, OFFSET(time_base),           AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, FLAGS },
@@ -298,7 +396,7 @@ static av_cold int init_audio(AVFilterContext *ctx, const char *args)
         goto fail;
     }
 
-    if (!(s->fifo = av_fifo_alloc(sizeof(AVFilterBufferRef*)))) {
+    if (!(s->fifo = av_fifo_alloc(sizeof(AVFrame*)))) {
         ret = AVERROR(ENOMEM);
         goto fail;
     }
@@ -321,9 +419,9 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     BufferSourceContext *s = ctx->priv;
     while (s->fifo && av_fifo_size(s->fifo)) {
-        AVFilterBufferRef *buf;
-        av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
-        avfilter_unref_buffer(buf);
+        AVFrame *frame;
+        av_fifo_generic_read(s->fifo, &frame, sizeof(frame), NULL);
+        av_frame_free(&frame);
     }
     av_fifo_free(s->fifo);
     s->fifo = NULL;
@@ -387,7 +485,8 @@ static int config_props(AVFilterLink *link)
 static int request_frame(AVFilterLink *link)
 {
     BufferSourceContext *c = link->src->priv;
-    AVFilterBufferRef *buf;
+    AVFrame *frame;
+    int ret = 0;
 
     if (!av_fifo_size(c->fifo)) {
         if (c->eof)
@@ -395,9 +494,12 @@ static int request_frame(AVFilterLink *link)
         c->nb_failed_requests++;
         return AVERROR(EAGAIN);
     }
-    av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL);
+    av_fifo_generic_read(c->fifo, &frame, sizeof(frame), NULL);
 
-    return ff_filter_frame(link, buf);
+    /* CIG TODO do not ignore error */
+    ff_filter_frame(link, frame);
+
+    return ret;
 }
 
 static int poll_frame(AVFilterLink *link)
@@ -406,7 +508,7 @@ static int poll_frame(AVFilterLink *link)
     int size = av_fifo_size(c->fifo);
     if (!size && c->eof)
         return AVERROR_EOF;
-    return size/sizeof(AVFilterBufferRef*);
+    return size/sizeof(AVFrame*);
 }
 
 static const AVFilterPad avfilter_vsrc_buffer_outputs[] = {
diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h
index 7f3c8d8ec3bb966ffa2ac818c5c7216151d13e39..3b9fd5282ce78219804857faba6bdcafbbf8b485 100644
--- a/libavfilter/buffersrc.h
+++ b/libavfilter/buffersrc.h
@@ -68,14 +68,15 @@ int av_buffersrc_add_ref(AVFilterContext *buffer_src,
  */
 unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src);
 
-#ifdef FF_API_BUFFERSRC_BUFFER
+#if FF_API_AVFILTERBUFFER
 /**
  * Add a buffer to the filtergraph s.
  *
  * @param buf buffer containing frame data to be passed down the filtergraph.
  * This function will take ownership of buf, the user must not free it.
  * A NULL buf signals EOF -- i.e. no more frames will be sent to this filter.
- * @deprecated Use av_buffersrc_add_ref(s, picref, AV_BUFFERSRC_FLAG_NO_COPY) instead.
+ *
+ * @deprecated use av_buffersrc_write_frame() or av_buffersrc_add_frame()
  */
 attribute_deprecated
 int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf);
@@ -85,11 +86,42 @@ int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf);
  * Add a frame to the buffer source.
  *
  * @param s an instance of the buffersrc filter.
- * @param frame frame to be added.
+ * @param frame frame to be added. If the frame is reference counted, this
+ * function will make a new reference to it. Otherwise the frame data will be
+ * copied.
  *
- * @warning frame data will be memcpy()ed, which may be a big performance
- *          hit. Use av_buffersrc_buffer() to avoid copying the data.
+ * @return 0 on success, a negative AVERROR on error
  */
 int av_buffersrc_write_frame(AVFilterContext *s, const AVFrame *frame);
 
+/**
+ * Add a frame to the buffer source.
+ *
+ * @param s an instance of the buffersrc filter.
+ * @param frame frame to be added. If the frame is reference counted, this
+ * function will take ownership of the reference(s) and reset the frame.
+ * Otherwise the frame data will be copied. If this function returns an error,
+ * the input frame is not touched.
+ *
+ * @return 0 on success, a negative AVERROR on error.
+ *
+ * @note the difference between this function and av_buffersrc_write_frame() is
+ * that av_buffersrc_write_frame() creates a new reference to the input frame,
+ * while this function takes ownership of the reference passed to it.
+ */
+int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame);
+
+/**
+ * Add frame data to buffer_src. XXX
+ *
+ * @param buffer_src  pointer to a buffer source context
+ * @param frame       a frame, or NULL to mark EOF
+ * @param flags       a combination of AV_BUFFERSRC_FLAG_*
+ * @return            >= 0 in case of success, a negative AVERROR code
+ *                    in case of failure
+ */
+int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src,
+                                 AVFrame *frame, int flags);
+
+
 #endif /* AVFILTER_BUFFERSRC_H */
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
index 66cc1337040fb9811f99b4dd25dde5ab9c23f8b7..05ea63033fe33e0823abc25119d9510471a58569 100644
--- a/libavfilter/f_ebur128.c
+++ b/libavfilter/f_ebur128.c
@@ -97,7 +97,7 @@ typedef struct {
     struct rect text;               ///< rectangle for the LU legend on the left
     struct rect graph;              ///< rectangle for the main graph in the center
     struct rect gauge;              ///< rectangle for the gauge on the right
-    AVFilterBufferRef *outpicref;   ///< output picture reference, updated regularly
+    AVFrame *outpicref;             ///< output picture reference, updated regularly
     int meter;                      ///< select a EBU mode between +9 and +18
     int scale_range;                ///< the range of LU values according to the meter
     int y_zero_lu;                  ///< the y value (pixel position) for 0 LU
@@ -174,7 +174,7 @@ static const uint8_t font_colors[] = {
     0x00, 0x96, 0x96,
 };
 
-static void drawtext(AVFilterBufferRef *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt, ...)
+static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt, ...)
 {
     int i;
     char buf[128] = {0};
@@ -207,7 +207,7 @@ static void drawtext(AVFilterBufferRef *pic, int x, int y, int ftid, const uint8
     }
 }
 
-static void drawline(AVFilterBufferRef *pic, int x, int y, int len, int step)
+static void drawline(AVFrame *pic, int x, int y, int len, int step)
 {
     int i;
     uint8_t *p = pic->data[0] + y*pic->linesize[0] + x*3;
@@ -224,7 +224,7 @@ static int config_video_output(AVFilterLink *outlink)
     uint8_t *p;
     AVFilterContext *ctx = outlink->src;
     EBUR128Context *ebur128 = ctx->priv;
-    AVFilterBufferRef *outpicref;
+    AVFrame *outpicref;
 
     /* check if there is enough space to represent everything decently */
     if (ebur128->w < 640 || ebur128->h < 480) {
@@ -259,10 +259,9 @@ static int config_video_output(AVFilterLink *outlink)
     av_assert0(ebur128->graph.h == ebur128->gauge.h);
 
     /* prepare the initial picref buffer */
-    avfilter_unref_bufferp(&ebur128->outpicref);
+    av_frame_free(&ebur128->outpicref);
     ebur128->outpicref = outpicref =
-        ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_PRESERVE|AV_PERM_REUSE2,
-                            outlink->w, outlink->h);
+        ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!outpicref)
         return AVERROR(ENOMEM);
     outlink->sample_aspect_ratio = (AVRational){1,1};
@@ -450,15 +449,15 @@ static int gate_update(struct integrator *integ, double power,
     return gate_hist_pos;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
 {
     int i, ch, idx_insample;
     AVFilterContext *ctx = inlink->dst;
     EBUR128Context *ebur128 = ctx->priv;
     const int nb_channels = ebur128->nb_channels;
-    const int nb_samples  = insamples->audio->nb_samples;
+    const int nb_samples  = insamples->nb_samples;
     const double *samples = (double *)insamples->data[0];
-    AVFilterBufferRef *pic = ebur128->outpicref;
+    AVFrame *pic = ebur128->outpicref;
 
     for (idx_insample = 0; idx_insample < nb_samples; idx_insample++) {
         const int bin_id_400  = ebur128->i400.cache_pos;
@@ -639,7 +638,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *insamples)
 
                 /* set pts and push frame */
                 pic->pts = pts;
-                ret = ff_filter_frame(outlink, avfilter_ref_buffer(pic, ~AV_PERM_WRITE));
+                ret = ff_filter_frame(outlink, av_frame_clone(pic));
                 if (ret < 0)
                     return ret;
             }
@@ -738,7 +737,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     }
     for (i = 0; i < ctx->nb_outputs; i++)
         av_freep(&ctx->output_pads[i].name);
-    avfilter_unref_bufferp(&ebur128->outpicref);
+    av_frame_free(&ebur128->outpicref);
 }
 
 static const AVFilterPad ebur128_inputs[] = {
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index 0f211454ef78b711025f9d24af0f2343083969f4..36ef50744afc8fa30fd441e46aac40bfcb24b23b 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -134,7 +134,7 @@ typedef struct {
     DSPContext c;                   ///< context providing optimized SAD methods   (scene detect only)
     double prev_mafd;               ///< previous MAFD                             (scene detect only)
 #endif
-    AVFilterBufferRef *prev_picref; ///< previous frame                            (scene detect only)
+    AVFrame *prev_picref; ///< previous frame                            (scene detect only)
     double select;
 } SelectContext;
 
@@ -219,25 +219,25 @@ static int config_input(AVFilterLink *inlink)
 }
 
 #if CONFIG_AVCODEC
-static double get_scene_score(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static double get_scene_score(AVFilterContext *ctx, AVFrame *frame)
 {
     double ret = 0;
     SelectContext *select = ctx->priv;
-    AVFilterBufferRef *prev_picref = select->prev_picref;
+    AVFrame *prev_picref = select->prev_picref;
 
     if (prev_picref &&
-        picref->video->h    == prev_picref->video->h &&
-        picref->video->w    == prev_picref->video->w &&
-        picref->linesize[0] == prev_picref->linesize[0]) {
+        frame->height    == prev_picref->height &&
+        frame->width    == prev_picref->width &&
+        frame->linesize[0] == prev_picref->linesize[0]) {
         int x, y, nb_sad = 0;
         int64_t sad = 0;
         double mafd, diff;
-        uint8_t *p1 =      picref->data[0];
+        uint8_t *p1 =      frame->data[0];
         uint8_t *p2 = prev_picref->data[0];
-        const int linesize = picref->linesize[0];
+        const int linesize = frame->linesize[0];
 
-        for (y = 0; y < picref->video->h - 8; y += 8) {
-            for (x = 0; x < picref->video->w*3 - 8; x += 8) {
+        for (y = 0; y < frame->height - 8; y += 8) {
+            for (x = 0; x < frame->width*3 - 8; x += 8) {
                 sad += select->c.sad[1](select, p1 + x, p2 + x,
                                         linesize, 8);
                 nb_sad += 8 * 8;
@@ -250,9 +250,9 @@ static double get_scene_score(AVFilterContext *ctx, AVFilterBufferRef *picref)
         diff = fabs(mafd - select->prev_mafd);
         ret  = av_clipf(FFMIN(mafd, diff) / 100., 0, 1);
         select->prev_mafd = mafd;
-        avfilter_unref_buffer(prev_picref);
+        av_frame_free(&prev_picref);
     }
-    select->prev_picref = avfilter_ref_buffer(picref, ~0);
+    select->prev_picref = av_frame_clone(frame);
     return ret;
 }
 #endif
@@ -260,38 +260,38 @@ static double get_scene_score(AVFilterContext *ctx, AVFilterBufferRef *picref)
 #define D2TS(d)  (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
 
-static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *ref)
+static int select_frame(AVFilterContext *ctx, AVFrame *frame)
 {
     SelectContext *select = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
     double res;
 
     if (isnan(select->var_values[VAR_START_PTS]))
-        select->var_values[VAR_START_PTS] = TS2D(ref->pts);
+        select->var_values[VAR_START_PTS] = TS2D(frame->pts);
     if (isnan(select->var_values[VAR_START_T]))
-        select->var_values[VAR_START_T] = TS2D(ref->pts) * av_q2d(inlink->time_base);
+        select->var_values[VAR_START_T] = TS2D(frame->pts) * av_q2d(inlink->time_base);
 
-    select->var_values[VAR_PTS] = TS2D(ref->pts);
-    select->var_values[VAR_T  ] = TS2D(ref->pts) * av_q2d(inlink->time_base);
-    select->var_values[VAR_POS] = ref->pos == -1 ? NAN : ref->pos;
+    select->var_values[VAR_PTS] = TS2D(frame->pts);
+    select->var_values[VAR_T  ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
+    select->var_values[VAR_POS] = av_frame_get_pkt_pos(frame) == -1 ? NAN : av_frame_get_pkt_pos(frame);
 
     switch (inlink->type) {
     case AVMEDIA_TYPE_AUDIO:
-        select->var_values[VAR_SAMPLES_N] = ref->audio->nb_samples;
+        select->var_values[VAR_SAMPLES_N] = frame->nb_samples;
         break;
 
     case AVMEDIA_TYPE_VIDEO:
         select->var_values[VAR_INTERLACE_TYPE] =
-            !ref->video->interlaced ? INTERLACE_TYPE_P :
-        ref->video->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
-        select->var_values[VAR_PICT_TYPE] = ref->video->pict_type;
+            !frame->interlaced_frame ? INTERLACE_TYPE_P :
+        frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
+        select->var_values[VAR_PICT_TYPE] = frame->pict_type;
 #if CONFIG_AVCODEC
         if (select->do_scene_detect) {
             char buf[32];
-            select->var_values[VAR_SCENE] = get_scene_score(ctx, ref);
+            select->var_values[VAR_SCENE] = get_scene_score(ctx, frame);
             // TODO: document metadata
             snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]);
-            av_dict_set(&ref->metadata, "lavfi.scene_score", buf, 0);
+            av_dict_set(&frame->metadata, "lavfi.scene_score", buf, 0);
         }
 #endif
         break;
@@ -299,11 +299,10 @@ static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *ref)
 
     res = av_expr_eval(select->expr, select->var_values, NULL);
     av_log(inlink->dst, AV_LOG_DEBUG,
-           "n:%f pts:%f t:%f pos:%f key:%d",
+           "n:%f pts:%f t:%f key:%d",
            select->var_values[VAR_N],
            select->var_values[VAR_PTS],
            select->var_values[VAR_T],
-           select->var_values[VAR_POS],
            (int)select->var_values[VAR_KEY]);
 
     switch (inlink->type) {
@@ -330,7 +329,7 @@ static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *ref)
         select->var_values[VAR_PREV_SELECTED_T]   = select->var_values[VAR_T];
         select->var_values[VAR_SELECTED_N] += 1.0;
         if (inlink->type == AVMEDIA_TYPE_AUDIO)
-            select->var_values[VAR_CONSUMED_SAMPLES_N] += ref->audio->nb_samples;
+            select->var_values[VAR_CONSUMED_SAMPLES_N] += frame->nb_samples;
     }
 
     select->var_values[VAR_N] += 1.0;
@@ -340,7 +339,7 @@ static int select_frame(AVFilterContext *ctx, AVFilterBufferRef *ref)
     return res;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     SelectContext *select = inlink->dst->priv;
 
@@ -348,7 +347,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     if (select->select)
         return ff_filter_frame(inlink->dst->outputs[0], frame);
 
-    avfilter_unref_bufferp(&frame);
+    av_frame_free(&frame);
     return 0;
 }
 
@@ -378,7 +377,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 
 #if CONFIG_AVCODEC
     if (select->do_scene_detect) {
-        avfilter_unref_bufferp(&select->prev_picref);
+        av_frame_free(&select->prev_picref);
         if (select->avctx) {
             avcodec_close(select->avctx);
             av_freep(&select->avctx);
diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c
index b5cf01c32baf279b7b989e564ef4ddfaf6dc9bbe..a5a5f2e695068dc74ec90869d88d383dfa73f2c7 100644
--- a/libavfilter/f_sendcmd.c
+++ b/libavfilter/f_sendcmd.c
@@ -448,7 +448,7 @@ static void av_cold uninit(AVFilterContext *ctx)
     av_freep(&sendcmd->intervals);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
 {
     AVFilterContext *ctx = inlink->dst;
     SendCmdContext *sendcmd = ctx->priv;
diff --git a/libavfilter/f_setpts.c b/libavfilter/f_setpts.c
index 1c2edb826b67a8aacdcc490cede64ac3d877acbe..d3a297688f2a8470f7b14df858da152e0d4a03c2 100644
--- a/libavfilter/f_setpts.c
+++ b/libavfilter/f_setpts.c
@@ -138,7 +138,7 @@ static inline char *double2int64str(char *buf, double v)
 
 #define d2istr(v) double2int64str((char[BUF_SIZE]){0}, v)
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     SetPTSContext *setpts = inlink->dst->priv;
     int64_t in_pts = frame->pts;
@@ -150,16 +150,16 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     }
     setpts->var_values[VAR_PTS       ] = TS2D(frame->pts);
     setpts->var_values[VAR_T         ] = TS2T(frame->pts, inlink->time_base);
-    setpts->var_values[VAR_POS       ] = frame->pos == -1 ? NAN : frame->pos;
+    setpts->var_values[VAR_POS       ] = av_frame_get_pkt_pos(frame) == -1 ? NAN : av_frame_get_pkt_pos(frame);
     setpts->var_values[VAR_RTCTIME   ] = av_gettime();
 
     switch (inlink->type) {
     case AVMEDIA_TYPE_VIDEO:
-        setpts->var_values[VAR_INTERLACED] = frame->video->interlaced;
+        setpts->var_values[VAR_INTERLACED] = frame->interlaced_frame;
         break;
 
     case AVMEDIA_TYPE_AUDIO:
-        setpts->var_values[VAR_NB_SAMPLES] = frame->audio->nb_samples;
+        setpts->var_values[VAR_NB_SAMPLES] = frame->nb_samples;
         break;
     }
 
@@ -192,7 +192,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     setpts->var_values[VAR_PREV_OUTT]   = TS2T(frame->pts, inlink->time_base);
     setpts->var_values[VAR_N] += 1.0;
     if (setpts->type == AVMEDIA_TYPE_AUDIO) {
-        setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += frame->audio->nb_samples;
+        setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += frame->nb_samples;
     }
     return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
diff --git a/libavfilter/f_settb.c b/libavfilter/f_settb.c
index 99ea7a78267ffc408da6eb8e0398dd7950ba1521..436491e26fd6dbb3413e5a3991c2359dc8d9030f 100644
--- a/libavfilter/f_settb.c
+++ b/libavfilter/f_settb.c
@@ -103,7 +103,7 @@ static int config_output_props(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c
index 9597fb3255379675e88de04e3cf688a29ecf481f..5153752f061229028687ac68c971094c0917e4e1 100644
--- a/libavfilter/fifo.c
+++ b/libavfilter/fifo.c
@@ -35,7 +35,7 @@
 #include "video.h"
 
 typedef struct Buf {
-    AVFilterBufferRef *buf;
+    AVFrame *frame;
     struct Buf        *next;
 } Buf;
 
@@ -47,8 +47,8 @@ typedef struct {
      * When a specific number of output samples is requested, the partial
      * buffer is stored here
      */
-    AVFilterBufferRef *buf_out;
-    int allocated_samples;      ///< number of samples buf_out was allocated for
+    AVFrame *out;
+    int allocated_samples;      ///< number of samples out was allocated for
 } FifoContext;
 
 static av_cold int init(AVFilterContext *ctx, const char *args)
@@ -66,25 +66,25 @@ static av_cold void uninit(AVFilterContext *ctx)
 
     for (buf = fifo->root.next; buf; buf = tmp) {
         tmp = buf->next;
-        avfilter_unref_bufferp(&buf->buf);
+        av_frame_free(&buf->frame);
         av_free(buf);
     }
 
-    avfilter_unref_bufferp(&fifo->buf_out);
+    av_frame_free(&fifo->out);
 }
 
-static int add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int add_to_queue(AVFilterLink *inlink, AVFrame *frame)
 {
     FifoContext *fifo = inlink->dst->priv;
 
     fifo->last->next = av_mallocz(sizeof(Buf));
     if (!fifo->last->next) {
-        avfilter_unref_buffer(buf);
+        av_frame_free(&frame);
         return AVERROR(ENOMEM);
     }
 
     fifo->last = fifo->last->next;
-    fifo->last->buf = buf;
+    fifo->last->frame = frame;
 
     return 0;
 }
@@ -101,7 +101,7 @@ static void queue_pop(FifoContext *s)
 /**
  * Move data pointers and pts offset samples forward.
  */
-static void buffer_offset(AVFilterLink *link, AVFilterBufferRef *buf,
+static void buffer_offset(AVFilterLink *link, AVFrame *frame,
                           int offset)
 {
     int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
@@ -110,32 +110,32 @@ static void buffer_offset(AVFilterLink *link, AVFilterBufferRef *buf,
     int block_align = av_get_bytes_per_sample(link->format) * (planar ? 1 : nb_channels);
     int i;
 
-    av_assert0(buf->audio->nb_samples > offset);
+    av_assert0(frame->nb_samples > offset);
 
     for (i = 0; i < planes; i++)
-        buf->extended_data[i] += block_align*offset;
-    if (buf->data != buf->extended_data)
-        memcpy(buf->data, buf->extended_data,
-               FFMIN(planes, FF_ARRAY_ELEMS(buf->data)) * sizeof(*buf->data));
-    buf->linesize[0] -= block_align*offset;
-    buf->audio->nb_samples -= offset;
-
-    if (buf->pts != AV_NOPTS_VALUE) {
-        buf->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate},
-                                 link->time_base);
+        frame->extended_data[i] += block_align * offset;
+    if (frame->data != frame->extended_data)
+        memcpy(frame->data, frame->extended_data,
+               FFMIN(planes, FF_ARRAY_ELEMS(frame->data)) * sizeof(*frame->data));
+    frame->linesize[0] -= block_align*offset;
+    frame->nb_samples -= offset;
+
+    if (frame->pts != AV_NOPTS_VALUE) {
+        frame->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate},
+                                   link->time_base);
     }
 }
 
-static int calc_ptr_alignment(AVFilterBufferRef *buf)
+static int calc_ptr_alignment(AVFrame *frame)
 {
-    int planes = av_sample_fmt_is_planar(buf->format) ?
-                 av_get_channel_layout_nb_channels(buf->audio->channel_layout) : 1;
+    int planes = av_sample_fmt_is_planar(frame->format) ?
+                 av_get_channel_layout_nb_channels(frame->channel_layout) : 1;
     int min_align = 128;
     int p;
 
     for (p = 0; p < planes; p++) {
         int cur_align = 128;
-        while ((intptr_t)buf->extended_data[p] % cur_align)
+        while ((intptr_t)frame->extended_data[p] % cur_align)
             cur_align >>= 1;
         if (cur_align < min_align)
             min_align = cur_align;
@@ -147,35 +147,34 @@ static int return_audio_frame(AVFilterContext *ctx)
 {
     AVFilterLink *link = ctx->outputs[0];
     FifoContext *s = ctx->priv;
-    AVFilterBufferRef *head = s->root.next->buf;
-    AVFilterBufferRef *buf_out;
+    AVFrame *head = s->root.next->frame;
+    AVFrame *out;
     int ret;
 
-    if (!s->buf_out &&
-        head->audio->nb_samples >= link->request_samples &&
+    if (!s->out &&
+        head->nb_samples >= link->request_samples &&
         calc_ptr_alignment(head) >= 32) {
-        if (head->audio->nb_samples == link->request_samples) {
-            buf_out = head;
+        if (head->nb_samples == link->request_samples) {
+            out = head;
             queue_pop(s);
         } else {
-            buf_out = avfilter_ref_buffer(head, AV_PERM_READ);
-            if (!buf_out)
+            out = av_frame_clone(head);
+            if (!out)
                 return AVERROR(ENOMEM);
 
-            buf_out->audio->nb_samples = link->request_samples;
+            out->nb_samples = link->request_samples;
             buffer_offset(link, head, link->request_samples);
         }
     } else {
         int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
 
-        if (!s->buf_out) {
-            s->buf_out = ff_get_audio_buffer(link, AV_PERM_WRITE,
-                                             link->request_samples);
-            if (!s->buf_out)
+        if (!s->out) {
+            s->out = ff_get_audio_buffer(link, link->request_samples);
+            if (!s->out)
                 return AVERROR(ENOMEM);
 
-            s->buf_out->audio->nb_samples = 0;
-            s->buf_out->pts               = head->pts;
+            s->out->nb_samples = 0;
+            s->out->pts                   = head->pts;
             s->allocated_samples          = link->request_samples;
         } else if (link->request_samples != s->allocated_samples) {
             av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
@@ -183,41 +182,41 @@ static int return_audio_frame(AVFilterContext *ctx)
             return AVERROR(EINVAL);
         }
 
-        while (s->buf_out->audio->nb_samples < s->allocated_samples) {
-            int len = FFMIN(s->allocated_samples - s->buf_out->audio->nb_samples,
-                            head->audio->nb_samples);
+        while (s->out->nb_samples < s->allocated_samples) {
+            int len = FFMIN(s->allocated_samples - s->out->nb_samples,
+                            head->nb_samples);
 
-            av_samples_copy(s->buf_out->extended_data, head->extended_data,
-                            s->buf_out->audio->nb_samples, 0, len, nb_channels,
+            av_samples_copy(s->out->extended_data, head->extended_data,
+                            s->out->nb_samples, 0, len, nb_channels,
                             link->format);
-            s->buf_out->audio->nb_samples += len;
+            s->out->nb_samples += len;
 
-            if (len == head->audio->nb_samples) {
-                avfilter_unref_buffer(head);
+            if (len == head->nb_samples) {
+                av_frame_free(&head);
                 queue_pop(s);
 
                 if (!s->root.next &&
                     (ret = ff_request_frame(ctx->inputs[0])) < 0) {
                     if (ret == AVERROR_EOF) {
-                        av_samples_set_silence(s->buf_out->extended_data,
-                                               s->buf_out->audio->nb_samples,
+                        av_samples_set_silence(s->out->extended_data,
+                                               s->out->nb_samples,
                                                s->allocated_samples -
-                                               s->buf_out->audio->nb_samples,
+                                               s->out->nb_samples,
                                                nb_channels, link->format);
-                        s->buf_out->audio->nb_samples = s->allocated_samples;
+                        s->out->nb_samples = s->allocated_samples;
                         break;
                     }
                     return ret;
                 }
-                head = s->root.next->buf;
+                head = s->root.next->frame;
             } else {
                 buffer_offset(link, head, len);
             }
         }
-        buf_out = s->buf_out;
-        s->buf_out = NULL;
+        out = s->out;
+        s->out = NULL;
     }
-    return ff_filter_frame(link, buf_out);
+    return ff_filter_frame(link, out);
 }
 
 static int request_frame(AVFilterLink *outlink)
@@ -234,7 +233,7 @@ static int request_frame(AVFilterLink *outlink)
     if (outlink->request_samples) {
         return return_audio_frame(outlink->src);
     } else {
-        ret = ff_filter_frame(outlink, fifo->root.next->buf);
+        ret = ff_filter_frame(outlink, fifo->root.next->frame);
         queue_pop(fifo);
     }
 
@@ -247,7 +246,6 @@ static const AVFilterPad avfilter_vf_fifo_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = add_to_queue,
-        .min_perms        = AV_PERM_PRESERVE,
     },
     { NULL }
 };
@@ -280,7 +278,6 @@ static const AVFilterPad avfilter_af_afifo_inputs[] = {
         .type             = AVMEDIA_TYPE_AUDIO,
         .get_audio_buffer = ff_null_get_audio_buffer,
         .filter_frame     = add_to_queue,
-        .min_perms        = AV_PERM_PRESERVE,
     },
     { NULL }
 };
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index d03de56644dc5926c3e48921089a3b7e69966859..9a42ae08df2c5bf3de6de322d9e2104b4884ded9 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -67,33 +67,13 @@ struct AVFilterPad {
      */
     enum AVMediaType type;
 
-    /**
-     * Minimum required permissions on incoming buffers. Any buffer with
-     * insufficient permissions will be automatically copied by the filter
-     * system to a new buffer which provides the needed access permissions.
-     *
-     * Input pads only.
-     */
-    int min_perms;
-
-    /**
-     * Permissions which are not accepted on incoming buffers. Any buffer
-     * which has any of these permissions set will be automatically copied
-     * by the filter system to a new buffer which does not have those
-     * permissions. This can be used to easily disallow buffers with
-     * AV_PERM_REUSE.
-     *
-     * Input pads only.
-     */
-    int rej_perms;
-
     /**
      * Callback function to get a video buffer. If NULL, the filter system will
      * use ff_default_get_video_buffer().
      *
      * Input video pads only.
      */
-    AVFilterBufferRef *(*get_video_buffer)(AVFilterLink *link, int perms, int w, int h);
+    AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);
 
     /**
      * Callback function to get an audio buffer. If NULL, the filter system will
@@ -101,8 +81,7 @@ struct AVFilterPad {
      *
      * Input audio pads only.
      */
-    AVFilterBufferRef *(*get_audio_buffer)(AVFilterLink *link, int perms,
-                                           int nb_samples);
+    AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
 
     /**
      * Filtering callback. This is where a filter receives a frame with
@@ -114,7 +93,7 @@ struct AVFilterPad {
      * must ensure that samplesref is properly unreferenced on error if it
      * hasn't been passed on to another filter.
      */
-    int (*filter_frame)(AVFilterLink *link, AVFilterBufferRef *frame);
+    int (*filter_frame)(AVFilterLink *link, AVFrame *frame);
 
     /**
      * Frame poll callback. This returns the number of immediately available
@@ -234,8 +213,6 @@ int ff_parse_channel_layout(int64_t *ret, const char *arg, void *log_ctx);
 
 void ff_update_link_current_pts(AVFilterLink *link, int64_t pts);
 
-void ff_free_pool(AVFilterPool *pool);
-
 void ff_command_queue_pop(AVFilterContext *filter);
 
 /* misc trace functions */
@@ -252,7 +229,7 @@ void ff_command_queue_pop(AVFilterContext *filter);
 
 char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms);
 
-void ff_tlog_ref(void *ctx, AVFilterBufferRef *ref, int end);
+void ff_tlog_ref(void *ctx, AVFrame *ref, int end);
 
 void ff_tlog_link(void *ctx, AVFilterLink *link, int end);
 
@@ -346,6 +323,6 @@ int ff_buffersink_read_samples_compat(AVFilterContext *ctx, AVFilterBufferRef **
  * @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);
+int ff_filter_frame(AVFilterLink *link, AVFrame *frame);
 
 #endif /* AVFILTER_INTERNAL_H */
diff --git a/libavfilter/sink_buffer.c b/libavfilter/sink_buffer.c
index 9a99b5653663d78844fb1c3e077a535a277a7f04..07e4d04e45107f02554af708645ffeaf03203bff 100644
--- a/libavfilter/sink_buffer.c
+++ b/libavfilter/sink_buffer.c
@@ -31,6 +31,8 @@
 #include "audio.h"
 #include "internal.h"
 
+#include "libavutil/audio_fifo.h"
+
 AVBufferSinkParams *av_buffersink_params_alloc(void)
 {
     static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
@@ -88,14 +90,14 @@ static av_cold void common_uninit(AVFilterContext *ctx)
     if (buf->fifo) {
         while (av_fifo_size(buf->fifo) >= sizeof(AVFilterBufferRef *)) {
             av_fifo_generic_read(buf->fifo, &picref, sizeof(picref), NULL);
-            avfilter_unref_buffer(picref);
+            av_frame_unref(picref);
         }
         av_fifo_free(buf->fifo);
         buf->fifo = NULL;
     }
 }
 
-static int add_buffer_ref(AVFilterContext *ctx, AVFilterBufferRef *ref)
+static int add_buffer_ref(AVFilterContext *ctx, AVFrame *ref)
 {
     BufferSinkContext *buf = ctx->priv;
 
@@ -114,7 +116,7 @@ static int add_buffer_ref(AVFilterContext *ctx, AVFilterBufferRef *ref)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
 {
     AVFilterContext *ctx = inlink->dst;
     BufferSinkContext *buf = inlink->dst->priv;
@@ -141,18 +143,12 @@ void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
     inlink->partial_buf_size = frame_size;
 }
 
-int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
-                                  AVFilterBufferRef **bufref, int flags)
+int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
 {
     BufferSinkContext *buf = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
     int ret;
-    *bufref = NULL;
-
-    av_assert0(    !strcmp(ctx->filter->name, "buffersink")
-                || !strcmp(ctx->filter->name, "abuffersink")
-                || !strcmp(ctx->filter->name, "ffbuffersink")
-                || !strcmp(ctx->filter->name, "ffabuffersink"));
+    AVFrame *cur_frame;
 
     /* no picref available, fetch it from the filterchain */
     if (!av_fifo_size(buf->fifo)) {
@@ -165,13 +161,114 @@ int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
     if (!av_fifo_size(buf->fifo))
         return AVERROR(EINVAL);
 
-    if (flags & AV_BUFFERSINK_FLAG_PEEK)
-        *bufref = *((AVFilterBufferRef **)av_fifo_peek2(buf->fifo, 0));
+    if (flags & AV_BUFFERSINK_FLAG_PEEK) {
+        cur_frame = *((AVFrame **)av_fifo_peek2(buf->fifo, 0));
+        av_frame_ref(frame, cur_frame); /* TODO check failure */
+    } else {
+        av_fifo_generic_read(buf->fifo, &cur_frame, sizeof(cur_frame), NULL);
+        av_frame_move_ref(frame, cur_frame);
+        av_frame_free(&cur_frame);
+    }
+
+    return 0;
+}
+
+int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
+{
+    return av_buffersink_get_frame_flags(ctx, frame, 0);
+}
+
+int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples)
+{
+    av_assert0(!"TODO");
+}
+
+#if FF_API_AVFILTERBUFFER
+static void compat_free_buffer(AVFilterBuffer *buf)
+{
+    AVFrame *frame = buf->priv;
+    av_frame_free(&frame);
+    av_free(buf);
+}
+
+static int compat_read(AVFilterContext *ctx, AVFilterBufferRef **pbuf, int nb_samples, int flags)
+{
+    AVFilterBufferRef *buf;
+    AVFrame *frame;
+    int ret;
+
+    if (!pbuf)
+        return ff_poll_frame(ctx->inputs[0]);
+
+    frame = av_frame_alloc();
+    if (!frame)
+        return AVERROR(ENOMEM);
+
+    if (!nb_samples)
+        ret = av_buffersink_get_frame_flags(ctx, frame, flags);
     else
-        av_fifo_generic_read(buf->fifo, bufref, sizeof(*bufref), NULL);
+        ret = av_buffersink_get_samples(ctx, frame, nb_samples);
+
+    if (ret < 0)
+        goto fail;
+
+    if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) {
+        buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize,
+                                                        AV_PERM_READ,
+                                                        frame->width, frame->height,
+                                                        frame->format);
+    } else {
+        buf = avfilter_get_audio_buffer_ref_from_arrays(frame->extended_data,
+                                                        frame->linesize[0], AV_PERM_READ,
+                                                        frame->nb_samples,
+                                                        frame->format,
+                                                        frame->channel_layout);
+    }
+    if (!buf) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    avfilter_copy_frame_props(buf, frame);
+
+    buf->buf->priv = frame;
+    buf->buf->free = compat_free_buffer;
+
+    *pbuf = buf;
 
     return 0;
+fail:
+    av_frame_free(&frame);
+    return ret;
+}
+
+int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
+{
+    return compat_read(ctx, buf, 0, 0);
+}
+
+int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
+                               int nb_samples)
+{
+    return compat_read(ctx, buf, nb_samples, 0);
+}
+
+int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
+                                  AVFilterBufferRef **bufref, int flags)
+{
+    BufferSinkContext *buf = ctx->priv;
+    AVFilterLink *inlink = ctx->inputs[0];
+    int ret;
+    *bufref = NULL;
+
+    av_assert0(    !strcmp(ctx->filter->name, "buffersink")
+                || !strcmp(ctx->filter->name, "abuffersink")
+                || !strcmp(ctx->filter->name, "ffbuffersink")
+                || !strcmp(ctx->filter->name, "ffabuffersink"));
+
+    return compat_read(ctx, bufref, 0, flags);
 }
+#endif
 
 AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx)
 {
@@ -406,94 +503,3 @@ AVFilter avfilter_asink_abuffersink = {
     .inputs        = abuffersink_inputs,
     .outputs       = NULL,
 };
-
-/* Libav compatibility API */
-
-extern AVFilter avfilter_vsink_buffer;
-extern AVFilter avfilter_asink_abuffer;
-
-int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
-{
-    AVFilterBufferRef *tbuf;
-    int ret;
-
-    if (ctx->filter->          inputs[0].start_frame ==
-        avfilter_vsink_buffer. inputs[0].start_frame ||
-        ctx->filter->          inputs[0].filter_frame ==
-        avfilter_asink_abuffer.inputs[0].filter_frame)
-        return ff_buffersink_read_compat(ctx, buf);
-    av_assert0(ctx->filter->                inputs[0].end_frame ==
-               avfilter_vsink_ffbuffersink. inputs[0].end_frame ||
-               ctx->filter->                inputs[0].filter_frame ==
-               avfilter_asink_ffabuffersink.inputs[0].filter_frame);
-
-    ret = av_buffersink_get_buffer_ref(ctx, &tbuf,
-                                       buf ? 0 : AV_BUFFERSINK_FLAG_PEEK);
-    if (!buf)
-        return ret >= 0;
-    if (ret < 0)
-        return ret;
-    *buf = tbuf;
-    return 0;
-}
-
-int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
-                               int nb_samples)
-{
-    BufferSinkContext *sink = ctx->priv;
-    int ret = 0, have_samples = 0, need_samples;
-    AVFilterBufferRef *tbuf, *in_buf;
-    AVFilterLink *link = ctx->inputs[0];
-    int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
-
-    if (ctx->filter->          inputs[0].filter_frame ==
-        avfilter_asink_abuffer.inputs[0].filter_frame)
-        return ff_buffersink_read_samples_compat(ctx, buf, nb_samples);
-    av_assert0(ctx->filter->                inputs[0].filter_frame ==
-               avfilter_asink_ffabuffersink.inputs[0].filter_frame);
-
-    tbuf = ff_get_audio_buffer(link, AV_PERM_WRITE, nb_samples);
-    if (!tbuf)
-        return AVERROR(ENOMEM);
-
-    while (have_samples < nb_samples) {
-        ret = av_buffersink_get_buffer_ref(ctx, &in_buf,
-                                           AV_BUFFERSINK_FLAG_PEEK);
-        if (ret < 0) {
-            if (ret == AVERROR_EOF && have_samples) {
-                nb_samples = have_samples;
-                ret = 0;
-            }
-            break;
-        }
-
-        need_samples = FFMIN(in_buf->audio->nb_samples,
-                             nb_samples - have_samples);
-        av_samples_copy(tbuf->extended_data, in_buf->extended_data,
-                        have_samples, 0, need_samples,
-                        nb_channels, in_buf->format);
-        have_samples += need_samples;
-        if (need_samples < in_buf->audio->nb_samples) {
-            in_buf->audio->nb_samples -= need_samples;
-            av_samples_copy(in_buf->extended_data, in_buf->extended_data,
-                            0, need_samples, in_buf->audio->nb_samples,
-                            nb_channels, in_buf->format);
-        } else {
-            av_buffersink_get_buffer_ref(ctx, &in_buf, 0);
-            avfilter_unref_buffer(in_buf);
-        }
-    }
-    tbuf->audio->nb_samples = have_samples;
-
-    if (ret < 0) {
-        av_assert0(!av_fifo_size(sink->fifo));
-        if (have_samples)
-            add_buffer_ref(ctx, tbuf);
-        else
-            avfilter_unref_buffer(tbuf);
-        return ret;
-    }
-
-    *buf = tbuf;
-    return 0;
-}
diff --git a/libavfilter/split.c b/libavfilter/split.c
index a54bef9db60613fe8e00832ddb1c2a4bdef6ef3f..fadbcc0ed1d65f9bd2bc6f8e900b11c3d340b192 100644
--- a/libavfilter/split.c
+++ b/libavfilter/split.c
@@ -68,17 +68,17 @@ static void split_uninit(AVFilterContext *ctx)
         av_freep(&ctx->output_pads[i].name);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     int i, ret = AVERROR_EOF;
 
     for (i = 0; i < ctx->nb_outputs; i++) {
-        AVFilterBufferRef *buf_out;
+        AVFrame *buf_out;
 
         if (ctx->outputs[i]->closed)
             continue;
-        buf_out = avfilter_ref_buffer(frame, ~AV_PERM_WRITE);
+        buf_out = av_frame_clone(frame);
         if (!buf_out) {
             ret = AVERROR(ENOMEM);
             break;
@@ -88,7 +88,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
         if (ret < 0)
             break;
     }
-    avfilter_unref_bufferp(&frame);
+    av_frame_free(&frame);
     return ret;
 }
 
diff --git a/libavfilter/src_buffer.c b/libavfilter/src_buffer.c
deleted file mode 100644
index a9970345ec5213290cb45cdc9e9385160c13e712..0000000000000000000000000000000000000000
--- a/libavfilter/src_buffer.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2008 Vitor Sessak
- * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
- * Copyright (c) 2011 Mina Nagy Zaki
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * memory buffer source filter
- */
-
-#include "avfilter.h"
-#include "internal.h"
-#include "audio.h"
-#include "avcodec.h"
-#include "buffersrc.h"
-#include "asrc_abuffer.h"
-#include "libavutil/avstring.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/fifo.h"
-#include "libavutil/imgutils.h"
-
-typedef struct {
-    AVFifoBuffer     *fifo;
-    AVRational        time_base;     ///< time_base to set in the output link
-    int eof;
-    unsigned          nb_failed_requests;
-
-    /* Video only */
-    AVFilterContext  *scale;
-    int               h, w;
-    enum AVPixelFormat  pix_fmt;
-    AVRational        sample_aspect_ratio;
-    char              sws_param[256];
-
-    /* Audio only */
-    // Audio format of incoming buffers
-    int sample_rate;
-    unsigned int sample_format;
-    int64_t channel_layout;
-
-    // Normalization filters
-    AVFilterContext *aconvert;
-    AVFilterContext *aresample;
-} BufferSourceContext;
-
-static void buf_free(AVFilterBuffer *ptr)
-{
-    av_free(ptr);
-    return;
-}
-
-int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *ctx,
-                                        AVFilterBufferRef *samplesref,
-                                        int av_unused flags)
-{
-    return av_buffersrc_add_ref(ctx, samplesref, AV_BUFFERSRC_FLAG_NO_COPY);
-}
-
-int av_asrc_buffer_add_samples(AVFilterContext *ctx,
-                               uint8_t *data[8], int linesize[8],
-                               int nb_samples, int sample_rate,
-                               int sample_fmt, int64_t channel_layout, int planar,
-                               int64_t pts, int av_unused flags)
-{
-    AVFilterBufferRef *samplesref;
-
-    if (!channel_layout)
-        return AVERROR(EINVAL);
-    samplesref = avfilter_get_audio_buffer_ref_from_arrays(
-                     data, linesize[0], AV_PERM_WRITE,
-                     nb_samples,
-                     sample_fmt, channel_layout);
-    if (!samplesref)
-        return AVERROR(ENOMEM);
-
-    samplesref->buf->free  = buf_free;
-    samplesref->pts = pts;
-    samplesref->audio->sample_rate = sample_rate;
-
-    AV_NOWARN_DEPRECATED(
-    return av_asrc_buffer_add_audio_buffer_ref(ctx, samplesref, 0);
-    )
-}
-
-int av_asrc_buffer_add_buffer(AVFilterContext *ctx,
-                              uint8_t *buf, int buf_size, int sample_rate,
-                              int sample_fmt, int64_t channel_layout, int planar,
-                              int64_t pts, int av_unused flags)
-{
-    uint8_t *data[8] = {0};
-    int linesize[8];
-    int nb_channels = av_get_channel_layout_nb_channels(channel_layout),
-        nb_samples  = buf_size / nb_channels / av_get_bytes_per_sample(sample_fmt);
-
-    av_samples_fill_arrays(data, linesize,
-                           buf, nb_channels, nb_samples,
-                           sample_fmt, 16);
-
-    AV_NOWARN_DEPRECATED(
-    return av_asrc_buffer_add_samples(ctx,
-                                      data, linesize, nb_samples,
-                                      sample_rate,
-                                      sample_fmt, channel_layout, planar,
-                                      pts, flags);
-    )
-}
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
index bd45766641a334a7da1466cfb6e04bb94e60a71d..75c201cd46313aa2095e1bc406c4b18e6f1b0e88 100644
--- a/libavfilter/src_movie.c
+++ b/libavfilter/src_movie.c
@@ -313,11 +313,6 @@ static av_cold int movie_common_init(AVFilterContext *ctx, const char *args, con
         }
     }
 
-    if (!(movie->frame = avcodec_alloc_frame()) ) {
-        av_log(log, AV_LOG_ERROR, "Failed to alloc frame\n");
-        return AVERROR(ENOMEM);
-    }
-
     av_log(ctx, AV_LOG_VERBOSE, "seek_point:%"PRIi64" format_name:%s file_name:%s stream_index:%d\n",
            movie->seek_point, movie->format_name, movie->file_name,
            movie->stream_index);
@@ -339,7 +334,7 @@ static av_cold void movie_uninit(AVFilterContext *ctx)
     av_freep(&movie->file_name);
     av_freep(&movie->st);
     av_freep(&movie->out_index);
-    avcodec_free_frame(&movie->frame);
+    av_frame_free(&movie->frame);
     if (movie->format_ctx)
         avformat_close_input(&movie->format_ctx);
 }
@@ -399,54 +394,34 @@ static int movie_config_output_props(AVFilterLink *outlink)
     return 0;
 }
 
-static AVFilterBufferRef *frame_to_buf(enum AVMediaType type, AVFrame *frame,
-                                       AVFilterLink *outlink)
-{
-    AVFilterBufferRef *buf, *copy;
-
-    buf = avfilter_get_buffer_ref_from_frame(type, frame,
-                                             AV_PERM_WRITE |
-                                             AV_PERM_PRESERVE |
-                                             AV_PERM_REUSE2);
-    if (!buf)
-        return NULL;
-    buf->pts = av_frame_get_best_effort_timestamp(frame);
-    copy = ff_copy_buffer_ref(outlink, buf);
-    if (!copy)
-        return NULL;
-    buf->buf->data[0] = NULL; /* it belongs to the frame */
-    avfilter_unref_buffer(buf);
-    return copy;
-}
-
-static char *describe_bufref_to_str(char *dst, size_t dst_size,
-                                    AVFilterBufferRef *buf,
+static char *describe_frame_to_str(char *dst, size_t dst_size,
+                                    AVFrame *frame,
                                     AVFilterLink *link)
 {
-    switch (buf->type) {
+    switch (frame->type) {
     case AVMEDIA_TYPE_VIDEO:
         snprintf(dst, dst_size,
-                 "video pts:%s time:%s pos:%"PRId64" size:%dx%d aspect:%d/%d",
-                 av_ts2str(buf->pts), av_ts2timestr(buf->pts, &link->time_base),
-                 buf->pos, buf->video->w, buf->video->h,
-                 buf->video->sample_aspect_ratio.num,
-                 buf->video->sample_aspect_ratio.den);
+                 "video pts:%s time:%s size:%dx%d aspect:%d/%d",
+                 av_ts2str(frame->pts), av_ts2timestr(frame->pts, &link->time_base),
+                 frame->width, frame->height,
+                 frame->sample_aspect_ratio.num,
+                 frame->sample_aspect_ratio.den);
                  break;
     case AVMEDIA_TYPE_AUDIO:
         snprintf(dst, dst_size,
-                 "audio pts:%s time:%s pos:%"PRId64" samples:%d",
-                 av_ts2str(buf->pts), av_ts2timestr(buf->pts, &link->time_base),
-                 buf->pos, buf->audio->nb_samples);
+                 "audio pts:%s time:%s samples:%d",
+                 av_ts2str(frame->pts), av_ts2timestr(frame->pts, &link->time_base),
+                 frame->nb_samples);
                  break;
     default:
-        snprintf(dst, dst_size, "%s BUG", av_get_media_type_string(buf->type));
+        snprintf(dst, dst_size, "%s BUG", av_get_media_type_string(frame->type));
         break;
     }
     return dst;
 }
 
-#define describe_bufref(buf, link) \
-    describe_bufref_to_str((char[1024]){0}, 1024, buf, link)
+#define describe_frameref(f, link) \
+    describe_frame_to_str((char[1024]){0}, 1024, f, link)
 
 static int rewind_file(AVFilterContext *ctx)
 {
@@ -489,7 +464,6 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
     MovieStream *st;
     int ret, got_frame = 0, pkt_out_id;
     AVFilterLink *outlink;
-    AVFilterBufferRef *buf;
 
     if (!pkt->size) {
         if (movie->eof) {
@@ -532,6 +506,10 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
     st = &movie->st[pkt_out_id];
     outlink = ctx->outputs[pkt_out_id];
 
+    movie->frame = av_frame_alloc();
+    if (!movie->frame)
+        return AVERROR(ENOMEM);
+
     switch (st->st->codec->codec_type) {
     case AVMEDIA_TYPE_VIDEO:
         ret = avcodec_decode_video2(st->st->codec, movie->frame, &got_frame, pkt);
@@ -545,6 +523,7 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
     }
     if (ret < 0) {
         av_log(ctx, AV_LOG_WARNING, "Decode error: %s\n", av_err2str(ret));
+        av_frame_free(&movie->frame);
         return 0;
     }
     if (!ret)
@@ -560,23 +539,16 @@ static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
     if (!got_frame) {
         if (!ret)
             st->done = 1;
+        av_frame_free(&movie->frame);
         return 0;
     }
 
-    buf = frame_to_buf(st->st->codec->codec_type, movie->frame, outlink);
-    if (!buf)
-        return AVERROR(ENOMEM);
     av_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name,
-            describe_bufref(buf, outlink));
-    switch (st->st->codec->codec_type) {
-    case AVMEDIA_TYPE_VIDEO:
-        if (!movie->frame->sample_aspect_ratio.num)
-            buf->video->sample_aspect_ratio = st->st->sample_aspect_ratio;
-        /* Fall through */
-    case AVMEDIA_TYPE_AUDIO:
-        ff_filter_frame(outlink, buf);
-        break;
-    }
+            describe_frameref(movie->frame, outlink));
+
+    movie->frame->pts = av_frame_get_best_effort_timestamp(movie->frame);
+    ff_filter_frame(outlink, movie->frame); // FIXME: raise error properly
+    movie->frame = NULL;
 
     return pkt_out_id == out_id;
 }
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 29bc060072af7ce1956573feb55b5cd4c899d8d8..f9ae0b991b71776e3a1f4bd79868d6aa7b6c2c55 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -60,5 +60,8 @@
 #ifndef FF_API_BUFFERSRC_BUFFER
 #define FF_API_BUFFERSRC_BUFFER             (LIBAVFILTER_VERSION_MAJOR < 4)
 #endif
+#ifndef FF_API_AVFILTERBUFFER
+#define FF_API_AVFILTERBUFFER               (LIBAVFILTER_VERSION_MAJOR < 4)
+#endif
 
 #endif /* AVFILTER_VERSION_H */
diff --git a/libavfilter/vf_alphaextract.c b/libavfilter/vf_alphaextract.c
index 45d3dd46d73c0f36e30c36ee5afcd87028a99060..8fff80581b518dd37a2b7d9ad2c2081ccda20410 100644
--- a/libavfilter/vf_alphaextract.c
+++ b/libavfilter/vf_alphaextract.c
@@ -60,19 +60,18 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *cur_buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *cur_buf)
 {
     AlphaExtractContext *extract = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out_buf =
-        ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    AVFrame *out_buf = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     int ret;
 
     if (!out_buf) {
         ret = AVERROR(ENOMEM);
         goto end;
     }
-    avfilter_copy_buffer_ref_props(out_buf, cur_buf);
+    av_frame_copy_props(out_buf, cur_buf);
 
     if (extract->is_packed_rgb) {
         int x, y;
@@ -99,7 +98,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *cur_buf)
     ret = ff_filter_frame(outlink, out_buf);
 
 end:
-    avfilter_unref_buffer(cur_buf);
+    av_frame_unref(cur_buf);
     return ret;
 }
 
@@ -109,7 +108,6 @@ static const AVFilterPad alphaextract_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c
index 99fd61ee1525a20cfab6c32880664c76429d20b8..ead7ca7581750065b6eb1ee5319f61a8fd9408ed 100644
--- a/libavfilter/vf_alphamerge.c
+++ b/libavfilter/vf_alphamerge.c
@@ -96,11 +96,11 @@ static int config_output(AVFilterLink *outlink)
 }
 
 static void draw_frame(AVFilterContext *ctx,
-                       AVFilterBufferRef *main_buf,
-                       AVFilterBufferRef *alpha_buf)
+                       AVFrame *main_buf,
+                       AVFrame *alpha_buf)
 {
     AlphaMergeContext *merge = ctx->priv;
-    int h = main_buf->video->h;
+    int h = main_buf->height;
 
     if (merge->is_packed_rgb) {
         int x, y;
@@ -108,7 +108,7 @@ static void draw_frame(AVFilterContext *ctx,
         for (y = 0; y < h; y++) {
             pin = alpha_buf->data[0] + y * alpha_buf->linesize[0];
             pout = main_buf->data[0] + y * main_buf->linesize[0] + merge->rgba_map[A];
-            for (x = 0; x < main_buf->video->w; x++) {
+            for (x = 0; x < main_buf->width; x++) {
                 *pout = *pin;
                 pin += 1;
                 pout += 4;
@@ -118,7 +118,7 @@ static void draw_frame(AVFilterContext *ctx,
         int y;
         const int main_linesize = main_buf->linesize[A];
         const int alpha_linesize = alpha_buf->linesize[Y];
-        for (y = 0; y < h && y < alpha_buf->video->h; y++) {
+        for (y = 0; y < h && y < alpha_buf->height; y++) {
             memcpy(main_buf->data[A] + y * main_linesize,
                    alpha_buf->data[Y] + y * alpha_linesize,
                    FFMIN(main_linesize, alpha_linesize));
@@ -126,7 +126,7 @@ static void draw_frame(AVFilterContext *ctx,
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     AlphaMergeContext *merge = ctx->priv;
@@ -137,7 +137,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     ff_bufqueue_add(ctx, queue, buf);
 
     while (1) {
-        AVFilterBufferRef *main_buf, *alpha_buf;
+        AVFrame *main_buf, *alpha_buf;
 
         if (!ff_bufqueue_peek(&merge->queue_main, 0) ||
             !ff_bufqueue_peek(&merge->queue_alpha, 0)) break;
@@ -148,7 +148,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
         merge->frame_requested = 0;
         draw_frame(ctx, main_buf, alpha_buf);
         ff_filter_frame(ctx->outputs[0], main_buf);
-        avfilter_unref_buffer(alpha_buf);
+        av_frame_free(&alpha_buf);
     }
     return 0;
 }
diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c
index 8e19162cd2db54d649ea772cae06b8c37b2f41f2..710b81f630f249966d12a0f0c2c53c46908e133d 100644
--- a/libavfilter/vf_aspect.c
+++ b/libavfilter/vf_aspect.c
@@ -80,11 +80,11 @@ static av_cold int init(AVFilterContext *ctx, const char *args, const AVClass *c
     return 0;
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     AspectContext *aspect = link->dst->priv;
 
-    frame->video->sample_aspect_ratio = aspect->ratio;
+    frame->sample_aspect_ratio = aspect->ratio;
     return ff_filter_frame(link->dst->outputs[0], frame);
 }
 
diff --git a/libavfilter/vf_bbox.c b/libavfilter/vf_bbox.c
index 33b96b5608c890008663ce22d8882ecabf813b29..a761b562637a1a02014de481151ec11c6370ceae 100644
--- a/libavfilter/vf_bbox.c
+++ b/libavfilter/vf_bbox.c
@@ -56,7 +56,7 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     BBoxContext *bbox = ctx->priv;
@@ -65,14 +65,14 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
 
     has_bbox =
         ff_calculate_bounding_box(&box,
-                                  picref->data[0], picref->linesize[0],
+                                  frame->data[0], frame->linesize[0],
                                   inlink->w, inlink->h, 16);
     w = box.x2 - box.x1 + 1;
     h = box.y2 - box.y1 + 1;
 
     av_log(ctx, AV_LOG_INFO,
            "n:%d pts:%s pts_time:%s", bbox->frame,
-           av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base));
+           av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
 
     if (has_bbox) {
         av_log(ctx, AV_LOG_INFO,
@@ -85,7 +85,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     av_log(ctx, AV_LOG_INFO, "\n");
 
     bbox->frame++;
-    return ff_filter_frame(inlink->dst->outputs[0], picref);
+    return ff_filter_frame(inlink->dst->outputs[0], frame);
 }
 
 static const AVFilterPad bbox_inputs[] = {
diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
index f2f2cfa231e60068b03b86a93cebeee0d3943d65..e8af624c4ced02151bb369f44f058d95389acea7 100644
--- a/libavfilter/vf_blackdetect.c
+++ b/libavfilter/vf_blackdetect.c
@@ -146,7 +146,7 @@ static int request_frame(AVFilterLink *outlink)
     return ret;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
     AVFilterContext *ctx = inlink->dst;
     BlackDetectContext *blackdetect = ctx->priv;
@@ -163,10 +163,10 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     picture_black_ratio = (double)blackdetect->nb_black_pixels / (inlink->w * inlink->h);
 
     av_log(ctx, AV_LOG_DEBUG,
-           "frame:%u picture_black_ratio:%f pos:%"PRId64" pts:%s t:%s type:%c\n",
+           "frame:%u picture_black_ratio:%f pts:%s t:%s type:%c\n",
            blackdetect->frame_count, picture_black_ratio,
-           picref->pos, av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
-           av_get_picture_type_char(picref->video->pict_type));
+           av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
+           av_get_picture_type_char(picref->pict_type));
 
     if (picture_black_ratio >= blackdetect->picture_black_ratio_th) {
         if (!blackdetect->black_started) {
diff --git a/libavfilter/vf_blackframe.c b/libavfilter/vf_blackframe.c
index cf1bcd31b1405cd0dc3501d384f9b1c827cef903..52c56d8bc2a9b6400a007baae929c3027b1fe8c5 100644
--- a/libavfilter/vf_blackframe.c
+++ b/libavfilter/vf_blackframe.c
@@ -81,7 +81,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     BlackFrameContext *blackframe = ctx->priv;
@@ -89,22 +89,22 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     int pblack = 0;
     uint8_t *p = frame->data[0];
 
-    for (i = 0; i < frame->video->h; i++) {
+    for (i = 0; i < frame->height; i++) {
         for (x = 0; x < inlink->w; x++)
             blackframe->nblack += p[x] < blackframe->bthresh;
         p += frame->linesize[0];
     }
 
-    if (frame->video->key_frame)
+    if (frame->key_frame)
         blackframe->last_keyframe = blackframe->frame;
 
     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 "
+        av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pts:%"PRId64" t:%f "
                "type:%c last_keyframe:%d\n",
-               blackframe->frame, pblack, frame->pos, frame->pts,
+               blackframe->frame, pblack, frame->pts,
                frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
-               av_get_picture_type_char(frame->video->pict_type), blackframe->last_keyframe);
+               av_get_picture_type_char(frame->pict_type), blackframe->last_keyframe);
 
     blackframe->frame++;
     blackframe->nblack = 0;
diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c
index 27d94b4e4a66ec8c46e793d193a1cfc33486be46..bc276d4a8f98de48498ce12f5d589c5037c8b760 100644
--- a/libavfilter/vf_blend.c
+++ b/libavfilter/vf_blend.c
@@ -368,9 +368,9 @@ static int request_frame(AVFilterLink *outlink)
 }
 
 static void blend_frame(AVFilterContext *ctx,
-                        AVFilterBufferRef *top_buf,
-                        AVFilterBufferRef *bottom_buf,
-                        AVFilterBufferRef *dst_buf)
+                        AVFrame *top_buf,
+                        AVFrame *bottom_buf,
+                        AVFrame *dst_buf)
 {
     BlendContext *b = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
@@ -380,8 +380,8 @@ static void blend_frame(AVFilterContext *ctx,
     for (plane = 0; dst_buf->data[plane]; plane++) {
         int hsub = plane == 1 || plane == 2 ? b->hsub : 0;
         int vsub = plane == 1 || plane == 2 ? b->vsub : 0;
-        int outw = dst_buf->video->w >> hsub;
-        int outh = dst_buf->video->h >> vsub;
+        int outw = dst_buf->width  >> hsub;
+        int outh = dst_buf->height >> vsub;
         uint8_t *dst    = dst_buf->data[plane];
         uint8_t *top    = top_buf->data[plane];
         uint8_t *bottom = bottom_buf->data[plane];
@@ -390,15 +390,15 @@ static void blend_frame(AVFilterContext *ctx,
         param->values[VAR_T]  = dst_buf->pts == AV_NOPTS_VALUE ? NAN : dst_buf->pts * av_q2d(inlink->time_base);
         param->values[VAR_W]  = outw;
         param->values[VAR_H]  = outh;
-        param->values[VAR_SW] = outw / dst_buf->video->w;
-        param->values[VAR_SH] = outh / dst_buf->video->h;
+        param->values[VAR_SW] = outw / dst_buf->width;
+        param->values[VAR_SH] = outh / dst_buf->height;
         param->blend(top, top_buf->linesize[plane],
                      bottom, bottom_buf->linesize[plane],
                      dst, dst_buf->linesize[plane], outw, outh, param);
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -411,7 +411,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
     ff_bufqueue_add(ctx, queue, buf);
 
     while (1) {
-        AVFilterBufferRef *top_buf, *bottom_buf, *out_buf;
+        AVFrame *top_buf, *bottom_buf, *out_buf;
 
         if (!ff_bufqueue_peek(&b->queue_top, TOP) ||
             !ff_bufqueue_peek(&b->queue_bottom, BOTTOM)) break;
@@ -419,18 +419,17 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
         top_buf = ff_bufqueue_get(&b->queue_top);
         bottom_buf = ff_bufqueue_get(&b->queue_bottom);
 
-        out_buf = ff_get_video_buffer(outlink, AV_PERM_WRITE,
-                                      outlink->w, outlink->h);
+        out_buf = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out_buf) {
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(out_buf, top_buf);
+        av_frame_copy_props(out_buf, top_buf);
 
         b->frame_requested = 0;
         blend_frame(ctx, top_buf, bottom_buf, out_buf);
         ret = ff_filter_frame(ctx->outputs[0], out_buf);
-        avfilter_unref_buffer(top_buf);
-        avfilter_unref_buffer(bottom_buf);
+        av_frame_free(&top_buf);
+        av_frame_free(&bottom_buf);
     }
     return ret;
 }
@@ -441,12 +440,10 @@ static const AVFilterPad blend_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input_top,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ | AV_PERM_PRESERVE,
     },{
         .name             = "bottom",
         .type             = AVMEDIA_TYPE_VIDEO,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ | AV_PERM_PRESERVE,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c
index a4ac50afd535bd05ac01fbb22c41f4a7c3b44d45..3c72ddb538586da2b806d8e660ec89909a8e6b5a 100644
--- a/libavfilter/vf_boxblur.c
+++ b/libavfilter/vf_boxblur.c
@@ -328,23 +328,23 @@ static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li
                    h, radius, power, temp);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     BoxBlurContext *boxblur = ctx->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int plane;
-    int cw = inlink->w >> boxblur->hsub, ch = in->video->h >> boxblur->vsub;
+    int cw = inlink->w >> boxblur->hsub, ch = in->height >> boxblur->vsub;
     int w[4] = { inlink->w, cw, cw, inlink->w };
-    int h[4] = { in->video->h, ch, ch, in->video->h };
+    int h[4] = { in->height, ch, ch, in->height };
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     for (plane = 0; in->data[plane] && plane < 4; plane++)
         hblur(out->data[plane], out->linesize[plane],
@@ -358,7 +358,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
               w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane],
               boxblur->temp);
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
 }
@@ -369,7 +369,6 @@ static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ
     },
     { NULL }
 };
diff --git a/libavfilter/vf_colormatrix.c b/libavfilter/vf_colormatrix.c
index 571b9d4597b152fb12cb682b4c2fd7ff9f8f1d9a..4daa58e44a97248c3dec61fe67ff6f25557641a2 100644
--- a/libavfilter/vf_colormatrix.c
+++ b/libavfilter/vf_colormatrix.c
@@ -183,12 +183,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
 }
 
 static void process_frame_uyvy422(ColorMatrixContext *color,
-                                  AVFilterBufferRef *dst, AVFilterBufferRef *src)
+                                  AVFrame *dst, AVFrame *src)
 {
     const unsigned char *srcp = src->data[0];
     const int src_pitch = src->linesize[0];
-    const int height = src->video->h;
-    const int width = src->video->w*2;
+    const int height = src->height;
+    const int width = src->width*2;
     unsigned char *dstp = dst->data[0];
     const int dst_pitch = dst->linesize[0];
     const int c2 = color->yuv_convert[color->mode][0][1];
@@ -215,15 +215,15 @@ static void process_frame_uyvy422(ColorMatrixContext *color,
 }
 
 static void process_frame_yuv422p(ColorMatrixContext *color,
-                                  AVFilterBufferRef *dst, AVFilterBufferRef *src)
+                                  AVFrame *dst, AVFrame *src)
 {
     const unsigned char *srcpU = src->data[1];
     const unsigned char *srcpV = src->data[2];
     const unsigned char *srcpY = src->data[0];
     const int src_pitchY  = src->linesize[0];
     const int src_pitchUV = src->linesize[1];
-    const int height = src->video->h;
-    const int width = src->video->w;
+    const int height = src->height;
+    const int width = src->width;
     unsigned char *dstpU = dst->data[1];
     unsigned char *dstpV = dst->data[2];
     unsigned char *dstpY = dst->data[0];
@@ -257,7 +257,7 @@ static void process_frame_yuv422p(ColorMatrixContext *color,
 }
 
 static void process_frame_yuv420p(ColorMatrixContext *color,
-                                  AVFilterBufferRef *dst, AVFilterBufferRef *src)
+                                  AVFrame *dst, AVFrame *src)
 {
     const unsigned char *srcpU = src->data[1];
     const unsigned char *srcpV = src->data[2];
@@ -265,8 +265,8 @@ static void process_frame_yuv420p(ColorMatrixContext *color,
     const unsigned char *srcpN = src->data[0] + src->linesize[0];
     const int src_pitchY  = src->linesize[0];
     const int src_pitchUV = src->linesize[1];
-    const int height = src->video->h;
-    const int width = src->video->w;
+    const int height = src->height;
+    const int width = src->width;
     unsigned char *dstpU = dst->data[1];
     unsigned char *dstpV = dst->data[2];
     unsigned char *dstpY = dst->data[0];
@@ -332,19 +332,19 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *link, AVFrame *in)
 {
     AVFilterContext *ctx = link->dst;
     ColorMatrixContext *color = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     if (in->format == AV_PIX_FMT_YUV422P)
         process_frame_yuv422p(color, out, in);
@@ -353,7 +353,7 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
     else
         process_frame_uyvy422(color, out, in);
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -362,7 +362,6 @@ static const AVFilterPad colormatrix_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input,
-        .min_perms        = AV_PERM_READ,
         .filter_frame     = filter_frame,
     },
     { NULL }
diff --git a/libavfilter/vf_copy.c b/libavfilter/vf_copy.c
index a25e282d0837312adfa775c771c7b321606dc14c..df7ec3120dd6c23c622f0a5d44c125a2e0c94b9b 100644
--- a/libavfilter/vf_copy.c
+++ b/libavfilter/vf_copy.c
@@ -21,17 +21,35 @@
  * copy video filter
  */
 
+#include "libavutil/imgutils.h"
 #include "libavutil/internal.h"
 #include "avfilter.h"
 #include "internal.h"
 #include "video.h"
 
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterLink *outlink = inlink->dst->outputs[0];
+    AVFrame *out = ff_get_video_buffer(outlink, in->width, in->height);
+
+    if (!out) {
+        av_frame_free(&in);
+        return AVERROR(ENOMEM);
+    }
+    av_frame_copy_props(out, in);
+    av_image_copy(out->data, out->linesize, in->data, in->linesize,
+                  in->format, in->width, in->height);
+
+    av_frame_free(&in);
+    return ff_filter_frame(outlink, out);
+}
+
 static const AVFilterPad avfilter_vf_copy_inputs[] = {
     {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .rej_perms        = ~0
+        .filter_frame     = filter_frame,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index 8df959555019bbc9f9f1aa572b4fe05212e71737..17487a29ccc54ebbd2281374c120a65f96b854f7 100644
--- a/libavfilter/vf_crop.c
+++ b/libavfilter/vf_crop.c
@@ -70,7 +70,6 @@ enum var_name {
     VAR_X,
     VAR_Y,
     VAR_N,
-    VAR_POS,
     VAR_T,
     VAR_VARS_NB
 };
@@ -198,7 +197,6 @@ static int config_input(AVFilterLink *link)
     crop->var_values[VAR_OUT_H] = crop->var_values[VAR_OH] = NAN;
     crop->var_values[VAR_N]     = 0;
     crop->var_values[VAR_T]     = NAN;
-    crop->var_values[VAR_POS]   = NAN;
 
     av_image_fill_max_pixsteps(crop->max_step, NULL, pix_desc);
     crop->hsub = pix_desc->log2_chroma_w;
@@ -277,19 +275,18 @@ static int config_output(AVFilterLink *link)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     AVFilterContext *ctx = link->dst;
     CropContext *crop = ctx->priv;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
     int i;
 
-    frame->video->w = crop->w;
-    frame->video->h = crop->h;
+    frame->width  = crop->w;
+    frame->height = crop->h;
 
     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);
diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index f91c5220b37e30492b6399fd680d2716d2e9caf8..33790684685e6f3fe570ea5475f1e6d9d1366e66 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -117,7 +117,7 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     CropDetectContext *cd = ctx->priv;
@@ -128,36 +128,36 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     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 = frame->video->w-1;
-            cd->y1 = frame->video->h-1;
+            cd->x1 = frame->width  - 1;
+            cd->y1 = frame->height - 1;
             cd->x2 = 0;
             cd->y2 = 0;
             cd->frame_nb = 1;
         }
 
         for (y = 0; y < cd->y1; y++) {
-            if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->video->w, bpp) > cd->limit) {
+            if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > cd->limit) {
                 cd->y1 = y;
                 break;
             }
         }
 
-        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) {
+        for (y = frame->height - 1; y > cd->y2; y--) {
+            if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > cd->limit) {
                 cd->y2 = y;
                 break;
             }
         }
 
         for (y = 0; y < cd->x1; y++) {
-            if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->video->h, bpp) > cd->limit) {
+            if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > cd->limit) {
                 cd->x1 = y;
                 break;
             }
         }
 
-        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) {
+        for (y = frame->width - 1; y > cd->x2; y--) {
+            if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > cd->limit) {
                 cd->x2 = y;
                 break;
             }
@@ -187,8 +187,8 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
         y += (shrink_by/2 + 1) & ~1;
 
         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, frame->pos, frame->pts,
+               "x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
+               cd->x1, cd->x2, cd->y1, cd->y2, w, h, x, y, frame->pts,
                frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
                w, h, x, y);
     }
diff --git a/libavfilter/vf_decimate.c b/libavfilter/vf_decimate.c
index c5761adcfad168e02ed5daf844f4cb2c861eaec3..f0e49c993fb303eb7e45006c357505f2c8cc1da3 100644
--- a/libavfilter/vf_decimate.c
+++ b/libavfilter/vf_decimate.c
@@ -47,7 +47,7 @@ typedef struct {
                                    ///< if negative: number of sequential frames which were not dropped
 
     int hsub, vsub;                ///< chroma subsampling values
-    AVFilterBufferRef *ref;        ///< reference picture
+    AVFrame *ref;                  ///< reference picture
     DSPContext dspctx;             ///< context providing optimized diff routines
     AVCodecContext *avctx;         ///< codec context required for the DSPContext
 } DecimateContext;
@@ -105,7 +105,7 @@ static int diff_planes(AVFilterContext *ctx,
  * different with respect to the reference frame ref.
  */
 static int decimate_frame(AVFilterContext *ctx,
-                          AVFilterBufferRef *cur, AVFilterBufferRef *ref)
+                          AVFrame *cur, AVFrame *ref)
 {
     DecimateContext *decimate = ctx->priv;
     int plane;
@@ -122,7 +122,7 @@ static int decimate_frame(AVFilterContext *ctx,
         int hsub = plane == 1 || plane == 2 ? decimate->hsub : 0;
         if (diff_planes(ctx,
                         cur->data[plane], ref->data[plane], ref->linesize[plane],
-                        ref->video->w>>hsub, ref->video->h>>vsub))
+                        ref->width>>hsub, ref->height>>vsub))
             return 0;
     }
 
@@ -155,7 +155,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
 static av_cold void uninit(AVFilterContext *ctx)
 {
     DecimateContext *decimate = ctx->priv;
-    avfilter_unref_bufferp(&decimate->ref);
+    av_frame_free(&decimate->ref);
     avcodec_close(decimate->avctx);
     av_opt_free(decimate);
     av_freep(&decimate->avctx);
@@ -189,7 +189,7 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *cur)
+static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
 {
     DecimateContext *decimate = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
@@ -198,11 +198,11 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *cur)
     if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) {
         decimate->drop_count = FFMAX(1, decimate->drop_count+1);
     } else {
-        avfilter_unref_buffer(decimate->ref);
+        av_frame_free(&decimate->ref);
         decimate->ref = cur;
         decimate->drop_count = FFMIN(-1, decimate->drop_count-1);
 
-        if (ret = ff_filter_frame(outlink, avfilter_ref_buffer(cur, ~AV_PERM_WRITE)) < 0)
+        if (ret = ff_filter_frame(outlink, av_frame_clone(cur)) < 0)
             return ret;
     }
 
@@ -213,7 +213,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *cur)
            decimate->drop_count);
 
     if (decimate->drop_count > 0)
-        avfilter_unref_buffer(cur);
+        av_frame_free(&cur);
 
     return 0;
 }
@@ -238,7 +238,6 @@ static const AVFilterPad decimate_inputs[] = {
         .get_video_buffer = ff_null_get_video_buffer,
         .config_props     = config_input,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ | AV_PERM_PRESERVE,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c
index bf0ac62117ca2c615b33f5d42cc5548ac93d9694..10dbc14120fdc730b77f8b3897b4e71ed79be709 100644
--- a/libavfilter/vf_delogo.c
+++ b/libavfilter/vf_delogo.c
@@ -209,27 +209,28 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     DelogoContext *delogo = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int hsub0 = desc->log2_chroma_w;
     int vsub0 = desc->log2_chroma_h;
     int direct = 0;
     int plane;
 
-    if (in->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(in)) {
         direct = 1;
         out = in;
     } else {
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out) {
-            avfilter_unref_bufferp(&in);
+            av_frame_free(&in);
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(out, in);
+
+        av_frame_copy_props(out, in);
     }
 
     for (plane = 0; plane < 4 && in->data[plane]; plane++) {
@@ -246,7 +247,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
     }
 
     if (!direct)
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
 }
@@ -257,7 +258,6 @@ static const AVFilterPad avfilter_vf_delogo_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_WRITE | AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c
index 26f92f4dff00f9a8c5713093b9e398700bd40b2b..318c3994738b6a6871e07ea2a235887e45b69c37 100644
--- a/libavfilter/vf_deshake.c
+++ b/libavfilter/vf_deshake.c
@@ -88,7 +88,7 @@ typedef struct {
 
 typedef struct {
     const AVClass *class;
-    AVFilterBufferRef *ref;    ///< Previous frame
+    AVFrame *ref;              ///< Previous frame
     int rx;                    ///< Maximum horizontal shift
     int ry;                    ///< Maximum vertical shift
     int edge;                  ///< Edge fill method
@@ -434,7 +434,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     DeshakeContext *deshake = ctx->priv;
 
-    avfilter_unref_buffer(deshake->ref);
+    av_frame_free(&deshake->ref);
     if (deshake->fp)
         fclose(deshake->fp);
     if (deshake->avctx)
@@ -443,22 +443,22 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_opt_free(deshake);
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *link, AVFrame *in)
 {
     DeshakeContext *deshake = link->dst->priv;
     AVFilterLink *outlink = link->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     Transform t = {{0},0}, orig = {{0},0};
     float matrix[9];
     float alpha = 2.0 / deshake->refcount;
     char tmp[256];
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     if (deshake->cx < 0 || deshake->cy < 0 || deshake->cw < 0 || deshake->ch < 0) {
         // Find the most likely global motion for the current frame
@@ -545,7 +545,7 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
     avfilter_transform(in->data[2], out->data[2], in->linesize[2], out->linesize[2], CHROMA_WIDTH(link), CHROMA_HEIGHT(link), matrix, INTERPOLATE_BILINEAR, deshake->edge);
 
     // Cleanup the old reference frame
-    avfilter_unref_buffer(deshake->ref);
+    av_frame_free(&deshake->ref);
 
     // Store the current frame as the reference frame for calculating the
     // motion of the next frame
diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c
index af8eca4d52a33a118abb8be25932e6a54e9b6718..41601b9fabba98d0b50b71e22ceef8cc28d67c2d 100644
--- a/libavfilter/vf_drawbox.c
+++ b/libavfilter/vf_drawbox.c
@@ -130,13 +130,13 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     DrawBoxContext *drawbox = inlink->dst->priv;
     int plane, x, y, xb = drawbox->x, yb = drawbox->y;
     unsigned char *row[4];
 
-    for (y = FFMAX(yb, 0); y < frame->video->h && y < (yb + drawbox->h); y++) {
+    for (y = FFMAX(yb, 0); y < frame->height && y < (yb + drawbox->h); y++) {
         row[0] = frame->data[0] + y * frame->linesize[0];
 
         for (plane = 1; plane < 3; plane++)
@@ -144,12 +144,12 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
                  frame->linesize[plane] * (y >> drawbox->vsub);
 
         if (drawbox->invert_color) {
-            for (x = FFMAX(xb, 0); x < xb + drawbox->w && x < frame->video->w; x++)
+            for (x = FFMAX(xb, 0); x < xb + drawbox->w && x < frame->width; x++)
                 if ((y - yb < drawbox->thickness-1) || (yb + drawbox->h - y < drawbox->thickness) ||
                     (x - xb < drawbox->thickness-1) || (xb + drawbox->w - x < drawbox->thickness))
                     row[0][x] = 0xff - row[0][x];
         } else {
-            for (x = FFMAX(xb, 0); x < xb + drawbox->w && x < frame->video->w; x++) {
+            for (x = FFMAX(xb, 0); x < xb + drawbox->w && x < frame->width; x++) {
                 double alpha = (double)drawbox->yuv_color[A] / 255;
 
                 if ((y - yb < drawbox->thickness-1) || (yb + drawbox->h - y < drawbox->thickness) ||
@@ -172,7 +172,7 @@ static const AVFilterPad avfilter_vf_drawbox_inputs[] = {
         .config_props     = config_input,
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_WRITE | AV_PERM_READ,
+        .needs_writable   = 1,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 2358e35c26a77817542bccb8a48e6f4d12327cc2..10dee14384d56952eb8c9684b0b671df83f209f1 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -784,7 +784,7 @@ static int expand_text(AVFilterContext *ctx)
     return 0;
 }
 
-static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
+static int draw_glyphs(DrawTextContext *dtext, AVFrame *frame,
                        int width, int height, const uint8_t rgbcolor[4], FFDrawColor *color, int x, int y)
 {
     char *text = dtext->expanded_text.str;
@@ -812,7 +812,7 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
         y1 = dtext->positions[i].y+dtext->y+y;
 
         ff_blend_mask(&dtext->dc, color,
-                      picref->data, picref->linesize, width, height,
+                      frame->data, frame->linesize, width, height,
                       glyph->bitmap.buffer, glyph->bitmap.pitch,
                       glyph->bitmap.width, glyph->bitmap.rows,
                       glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
@@ -822,7 +822,7 @@ static int draw_glyphs(DrawTextContext *dtext, AVFilterBufferRef *picref,
     return 0;
 }
 
-static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
+static int draw_text(AVFilterContext *ctx, AVFrame *frame,
                      int width, int height)
 {
     DrawTextContext *dtext = ctx->priv;
@@ -845,7 +845,7 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
     av_bprint_clear(bp);
 
     if(dtext->basetime != AV_NOPTS_VALUE)
-        now= picref->pts*av_q2d(ctx->inputs[0]->time_base) + dtext->basetime/1000000;
+        now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + dtext->basetime/1000000;
 
     switch (dtext->exp_mode) {
     case EXP_NONE:
@@ -962,23 +962,23 @@ static int draw_text(AVFilterContext *ctx, AVFilterBufferRef *picref,
     /* draw box */
     if (dtext->draw_box)
         ff_blend_rectangle(&dtext->dc, &dtext->boxcolor,
-                           picref->data, picref->linesize, width, height,
+                           frame->data, frame->linesize, width, height,
                            dtext->x, dtext->y, box_w, box_h);
 
     if (dtext->shadowx || dtext->shadowy) {
-        if ((ret = draw_glyphs(dtext, picref, width, height, dtext->shadowcolor.rgba,
+        if ((ret = draw_glyphs(dtext, frame, width, height, dtext->shadowcolor.rgba,
                                &dtext->shadowcolor, dtext->shadowx, dtext->shadowy)) < 0)
             return ret;
     }
 
-    if ((ret = draw_glyphs(dtext, picref, width, height, dtext->fontcolor.rgba,
+    if ((ret = draw_glyphs(dtext, frame, width, height, dtext->fontcolor.rgba,
                            &dtext->fontcolor, 0, 0)) < 0)
         return ret;
 
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -992,7 +992,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     dtext->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
         NAN : frame->pts * av_q2d(inlink->time_base);
 
-    draw_text(ctx, frame, frame->video->w, frame->video->h);
+    draw_text(ctx, frame, frame->width, frame->height);
 
     av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
            (int)dtext->var_values[VAR_N], dtext->var_values[VAR_T],
@@ -1011,8 +1011,7 @@ static const AVFilterPad avfilter_vf_drawtext_inputs[] = {
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = filter_frame,
         .config_props     = config_input,
-        .min_perms        = AV_PERM_WRITE |
-                            AV_PERM_READ,
+        .needs_writable   = 1,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
index 5837cccdfe2d051018b15c0c28f0daebf7d2e851..b582ab968547c867e35676bb4ca7b6308134659e 100644
--- a/libavfilter/vf_edgedetect.c
+++ b/libavfilter/vf_edgedetect.c
@@ -249,21 +249,21 @@ static void double_threshold(AVFilterContext *ctx, int w, int h,
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     EdgeDetectContext *edgedetect = ctx->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     uint8_t  *tmpbuf    = edgedetect->tmpbuf;
     uint16_t *gradients = edgedetect->gradients;
-    AVFilterBufferRef *out;
+    AVFrame *out;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     /* gaussian filter to reduce noise  */
     gaussian_blur(ctx, inlink->w, inlink->h,
@@ -287,7 +287,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
                      out->data[0], out->linesize[0],
                      tmpbuf,       inlink->w);
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -305,7 +305,6 @@ static const AVFilterPad edgedetect_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_props,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
      },
      { NULL }
 };
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index df222747be8de2618caee72cbd3dfde835806746..a74e6d8e966edadcd520e3893eba9a5f2eff75dc 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -178,7 +178,7 @@ static void fade_plane(int y, int h, int w,
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     FadeContext *fade = inlink->dst->priv;
     uint8_t *p;
@@ -189,21 +189,21 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
             // alpha only
             plane = fade->is_packed_rgb ? 0 : A; // alpha is on plane 0 for packed formats
                                                  // or plane 3 for planar formats
-            fade_plane(0, frame->video->h, inlink->w,
+            fade_plane(0, frame->height, inlink->w,
                        fade->factor, fade->black_level, fade->black_level_scaled,
                        fade->is_packed_rgb ? fade->rgba_map[A] : 0, // alpha offset for packed formats
                        fade->is_packed_rgb ? 4 : 1,                 // pixstep for 8 bit packed formats
                        1, frame->data[plane], frame->linesize[plane]);
         } else {
             /* luma or rgb plane */
-            fade_plane(0, frame->video->h, inlink->w,
+            fade_plane(0, frame->height, inlink->w,
                        fade->factor, fade->black_level, fade->black_level_scaled,
                        0, 1, // offset & pixstep for Y plane or RGB packed format
                        fade->bpp, frame->data[0], frame->linesize[0]);
             if (frame->data[1] && frame->data[2]) {
                 /* chroma planes */
                 for (plane = 1; plane < 3; plane++) {
-                    for (i = 0; i < frame->video->h; i++) {
+                    for (i = 0; i < frame->height; 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
@@ -234,7 +234,7 @@ static const AVFilterPad avfilter_vf_fade_inputs[] = {
         .config_props     = config_props,
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ | AV_PERM_WRITE,
+        .needs_writable   = 1,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_field.c b/libavfilter/vf_field.c
index 67c00258f33c53d35390994b10ad4d45d8cf44a0..fc7e043311718963fb92b753ddabc4af0d5b25a5 100644
--- a/libavfilter/vf_field.c
+++ b/libavfilter/vf_field.c
@@ -82,14 +82,14 @@ static int config_props_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     FieldContext *field = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
     int i;
 
-    inpicref->video->h = outlink->h;
-    inpicref->video->interlaced = 0;
+    inpicref->height = outlink->h;
+    inpicref->interlaced_frame = 0;
 
     for (i = 0; i < field->nb_planes; i++) {
         if (field->type == FIELD_TYPE_BOTTOM)
diff --git a/libavfilter/vf_fieldorder.c b/libavfilter/vf_fieldorder.c
index 06e0369962c2f6ad73fbf234ed4d1f9c5630d10c..bad61e1e7256c52b2e3d23565e3a23d9d1c38a81 100644
--- a/libavfilter/vf_fieldorder.c
+++ b/libavfilter/vf_fieldorder.c
@@ -113,15 +113,15 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
 {
     AVFilterContext   *ctx        = inlink->dst;
     AVFilterLink      *outlink    = ctx->outputs[0];
 
-    return ff_get_video_buffer(outlink, perms, w, h);
+    return ff_get_video_buffer(outlink, w, h);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext   *ctx     = inlink->dst;
     FieldOrderContext *s       = ctx->priv;
@@ -129,14 +129,14 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     int h, plane, line_step, line_size, line;
     uint8_t *data;
 
-    if (!frame->video->interlaced ||
-        frame->video->top_field_first == s->dst_tff)
+    if (!frame->interlaced_frame ||
+        frame->top_field_first == s->dst_tff)
         return ff_filter_frame(outlink, frame);
 
     av_dlog(ctx,
             "picture will move %s one line\n",
             s->dst_tff ? "up" : "down");
-    h = frame->video->h;
+    h = frame->height;
     for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
         line_step = frame->linesize[plane];
         line_size = s->line_size[plane];
@@ -148,7 +148,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
              *  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 < frame->video->h) {
+                if (1 + line < frame->height) {
                     memcpy(data, data + line_step, line_size);
                 } else {
                     memcpy(data, data - line_step - line_step, line_size);
@@ -172,7 +172,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
             }
         }
     }
-    frame->video->top_field_first = s->dst_tff;
+    frame->top_field_first = s->dst_tff;
 
     return ff_filter_frame(outlink, frame);
 }
@@ -184,7 +184,7 @@ static const AVFilterPad avfilter_vf_fieldorder_inputs[] = {
         .config_props     = config_input,
         .get_video_buffer = get_video_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ | AV_PERM_WRITE,
+        .needs_writable   = 1,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index 29eedc7cf52ea8ad2319814f38aed06271c1c589..15eb6564e98cabe5d069cbad6a14b8681eed2b8f 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -89,7 +89,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     }
     av_opt_free(s);
 
-    if (!(s->fifo = av_fifo_alloc(2*sizeof(AVFilterBufferRef*))))
+    if (!(s->fifo = av_fifo_alloc(2*sizeof(AVFrame*))))
         return AVERROR(ENOMEM);
 
     av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", s->framerate.num, s->framerate.den);
@@ -99,9 +99,9 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
 static void flush_fifo(AVFifoBuffer *fifo)
 {
     while (av_fifo_size(fifo)) {
-        AVFilterBufferRef *tmp;
+        AVFrame *tmp;
         av_fifo_generic_read(fifo, &tmp, sizeof(tmp), NULL);
-        avfilter_unref_buffer(tmp);
+        av_frame_free(&tmp);
     }
 }
 
@@ -109,7 +109,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     FPSContext *s = ctx->priv;
     if (s->fifo) {
-        s->drop += av_fifo_size(s->fifo) / sizeof(AVFilterBufferRef*);
+        s->drop += av_fifo_size(s->fifo) / sizeof(AVFrame*);
         flush_fifo(s->fifo);
         av_fifo_free(s->fifo);
     }
@@ -145,7 +145,7 @@ static int request_frame(AVFilterLink *outlink)
     if (ret == AVERROR_EOF && av_fifo_size(s->fifo)) {
         int i;
         for (i = 0; av_fifo_size(s->fifo); i++) {
-            AVFilterBufferRef *buf;
+            AVFrame *buf;
 
             av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL);
             buf->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base,
@@ -162,13 +162,13 @@ static int request_frame(AVFilterLink *outlink)
     return ret;
 }
 
-static int write_to_fifo(AVFifoBuffer *fifo, AVFilterBufferRef *buf)
+static int write_to_fifo(AVFifoBuffer *fifo, AVFrame *buf)
 {
     int ret;
 
     if (!av_fifo_space(fifo) &&
         (ret = av_fifo_realloc2(fifo, 2*av_fifo_size(fifo)))) {
-        avfilter_unref_bufferp(&buf);
+        av_frame_free(&buf);
         return ret;
     }
 
@@ -176,7 +176,7 @@ static int write_to_fifo(AVFifoBuffer *fifo, AVFilterBufferRef *buf)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
 {
     AVFilterContext    *ctx = inlink->dst;
     FPSContext           *s = ctx->priv;
@@ -196,7 +196,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
         } else {
             av_log(ctx, AV_LOG_WARNING, "Discarding initial frame(s) with no "
                    "timestamp.\n");
-            avfilter_unref_buffer(buf);
+            av_frame_free(&buf);
             s->drop++;
         }
         return 0;
@@ -213,8 +213,8 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 
     if (delta < 1) {
         /* drop the frame and everything buffered except the first */
-        AVFilterBufferRef *tmp;
-        int drop = av_fifo_size(s->fifo)/sizeof(AVFilterBufferRef*);
+        AVFrame *tmp;
+        int drop = av_fifo_size(s->fifo)/sizeof(AVFrame*);
 
         av_log(ctx, AV_LOG_DEBUG, "Dropping %d frame(s).\n", drop);
         s->drop += drop;
@@ -223,18 +223,18 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
         flush_fifo(s->fifo);
         ret = write_to_fifo(s->fifo, tmp);
 
-        avfilter_unref_buffer(buf);
+        av_frame_free(&buf);
         return ret;
     }
 
     /* can output >= 1 frames */
     for (i = 0; i < delta; i++) {
-        AVFilterBufferRef *buf_out;
+        AVFrame *buf_out;
         av_fifo_generic_read(s->fifo, &buf_out, sizeof(buf_out), NULL);
 
         /* duplicate the frame if needed */
         if (!av_fifo_size(s->fifo) && i < delta - 1) {
-            AVFilterBufferRef *dup = avfilter_ref_buffer(buf_out, ~0);
+            AVFrame *dup = av_frame_clone(buf_out);
 
             av_log(ctx, AV_LOG_DEBUG, "Duplicating frame.\n");
             if (dup)
@@ -243,8 +243,8 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
                 ret = AVERROR(ENOMEM);
 
             if (ret < 0) {
-                avfilter_unref_bufferp(&buf_out);
-                avfilter_unref_bufferp(&buf);
+                av_frame_free(&buf_out);
+                av_frame_free(&buf);
                 return ret;
             }
 
@@ -255,7 +255,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
                                     outlink->time_base) + s->frames_out;
 
         if ((ret = ff_filter_frame(outlink, buf_out)) < 0) {
-            avfilter_unref_bufferp(&buf);
+            av_frame_free(&buf);
             return ret;
         }
 
diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c
index f84819641781e2c9348a62bffe97cbaaf7aa1e23..ca68df66dc7cebdf01f21fbddbe44576ed2cc93d 100644
--- a/libavfilter/vf_framestep.c
+++ b/libavfilter/vf_framestep.c
@@ -66,7 +66,7 @@ static int config_output_props(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
 {
     FrameStepContext *framestep = inlink->dst->priv;
 
@@ -75,7 +75,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *ref)
         return ff_filter_frame(inlink->dst->outputs[0], ref);
     } else {
         framestep->frame_selected = 0;
-        avfilter_unref_buffer(ref);
+        av_frame_free(&ref);
         return 0;
     }
 }
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index 7ed78fa1d71d9e63b7561b8395efd38fdea121a1..d79dac105296881ed14a3a00f25ac44bb6c8f2d9 100644
--- a/libavfilter/vf_frei0r.c
+++ b/libavfilter/vf_frei0r.c
@@ -379,24 +379,24 @@ static int query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     Frei0rContext *frei0r = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_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);
+    av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
 }
@@ -407,7 +407,6 @@ static const AVFilterPad avfilter_vf_frei0r_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_props,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ
     },
     { NULL }
 };
@@ -487,19 +486,18 @@ static int source_config_props(AVFilterLink *outlink)
 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);
+    AVFrame *frame = ff_get_video_buffer(outlink, outlink->w, outlink->h);
 
-    if (!picref)
+    if (!frame)
         return AVERROR(ENOMEM);
 
-    picref->video->sample_aspect_ratio = (AVRational) {1, 1};
-    picref->pts = frei0r->pts++;
-    picref->pos = -1;
+    frame->sample_aspect_ratio = (AVRational) {1, 1};
+    frame->pts = frei0r->pts++;
 
-    frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}),
-                   NULL, (uint32_t *)picref->data[0]);
+    frei0r->update(frei0r->instance, av_rescale_q(frame->pts, frei0r->time_base, (AVRational){1,1000}),
+                   NULL, (uint32_t *)frame->data[0]);
 
-    return ff_filter_frame(outlink, picref);
+    return ff_filter_frame(outlink, frame);
 }
 
 static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = {
diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c
index 72ecda0af11ee0c1576937286b582009760f9618..373f0f01731f4ffe3ba3e09a51291aae75316efc 100644
--- a/libavfilter/vf_geq.c
+++ b/libavfilter/vf_geq.c
@@ -37,7 +37,7 @@ typedef struct {
     AVExpr *e[4];               ///< expressions for each plane
     char *expr_str[4];          ///< expression strings for each plane
     int framenum;               ///< frame counter
-    AVFilterBufferRef *picref;  ///< current input buffer
+    AVFrame *picref;            ///< current input buffer
     int hsub, vsub;             ///< chroma subsampling
     int planes;                 ///< number of planes
 } GEQContext;
@@ -59,11 +59,11 @@ static inline double getpix(void *priv, double x, double y, int plane)
 {
     int xi, yi;
     GEQContext *geq = priv;
-    AVFilterBufferRef *picref = geq->picref;
+    AVFrame *picref = geq->picref;
     const uint8_t *src = picref->data[plane];
     const int linesize = picref->linesize[plane];
-    const int w = picref->video->w >> ((plane == 1 || plane == 2) ? geq->hsub : 0);
-    const int h = picref->video->h >> ((plane == 1 || plane == 2) ? geq->vsub : 0);
+    const int w = picref->width  >> ((plane == 1 || plane == 2) ? geq->hsub : 0);
+    const int h = picref->height >> ((plane == 1 || plane == 2) ? geq->vsub : 0);
 
     if (!src)
         return 0;
@@ -163,24 +163,24 @@ static int geq_config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int geq_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     int plane;
     GEQContext *geq = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     double values[VAR_VARS_NB] = {
         [VAR_N] = geq->framenum++,
         [VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base),
     };
 
     geq->picref = in;
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     for (plane = 0; plane < geq->planes && out->data[plane]; plane++) {
         int x, y;
@@ -204,7 +204,7 @@ static int geq_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         }
     }
 
-    avfilter_unref_bufferp(&geq->picref);
+    av_frame_free(&geq->picref);
     return ff_filter_frame(outlink, out);
 }
 
@@ -224,7 +224,6 @@ static const AVFilterPad geq_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = geq_config_props,
         .filter_frame = geq_filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c
index 13154f09e56281065e0eceac5566c930508f4530..c749534ad9d795e8f6168b36e131b0a82d24e18f 100644
--- a/libavfilter/vf_gradfun.c
+++ b/libavfilter/vf_gradfun.c
@@ -197,23 +197,23 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     GradFunContext *gf = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int p, direct = 0;
 
-    if (in->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(in)) {
         direct = 1;
         out = in;
     } else {
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out) {
-            avfilter_unref_bufferp(&in);
+            av_frame_free(&in);
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(out, in);
+        av_frame_copy_props(out, in);
     }
 
     for (p = 0; p < 4 && in->data[p]; p++) {
@@ -233,7 +233,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
     }
 
     if (!direct)
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
 }
@@ -244,7 +244,6 @@ static const AVFilterPad avfilter_vf_gradfun_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c
index c3b92c25df0499d33ea7d53e1a889afcb9e29607..cb519811ecd70bce47bd7ef737083d977d29d457 100644
--- a/libavfilter/vf_hflip.c
+++ b/libavfilter/vf_hflip.c
@@ -70,21 +70,21 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx  = inlink->dst;
     FlipContext *flip     = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     uint8_t *inrow, *outrow;
     int i, j, plane, step, hsub, vsub;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     /* copy palette if required */
     if (av_pix_fmt_desc_get(inlink->format)->flags & PIX_FMT_PAL)
@@ -97,7 +97,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 
         outrow = out->data[plane];
         inrow  = in ->data[plane] + ((inlink->w >> hsub) - 1) * step;
-        for (i = 0; i < in->video->h >> vsub; i++) {
+        for (i = 0; i < in->height >> vsub; i++) {
             switch (step) {
             case 1:
                 for (j = 0; j < (inlink->w >> hsub); j++)
@@ -143,7 +143,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         }
     }
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -153,7 +153,6 @@ static const AVFilterPad avfilter_vf_hflip_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_props,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_histeq.c b/libavfilter/vf_histeq.c
index 556680c124c6dc99b1d1b73e248869ad6985d46c..a9cb60e84746411166b42347be127dedbea06fd7 100644
--- a/libavfilter/vf_histeq.c
+++ b/libavfilter/vf_histeq.c
@@ -142,7 +142,7 @@ static int config_input(AVFilterLink *inlink)
     b = src[x + map[B]];                       \
 } while (0)
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
 {
     AVFilterContext   *ctx     = inlink->dst;
     HisteqContext     *histeq  = ctx->priv;
@@ -150,16 +150,16 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
     int strength  = histeq->strength  * 1000;
     int intensity = histeq->intensity * 1000;
     int x, y, i, luthi, lutlo, lut, luma, oluma, m;
-    AVFilterBufferRef *outpic;
+    AVFrame *outpic;
     unsigned int r, g, b, jran;
     uint8_t *src, *dst;
 
-    outpic = ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN, outlink->w, outlink->h);
+    outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!outpic) {
-        avfilter_unref_bufferp(&inpic);
+        av_frame_free(&inpic);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(outpic, inpic);
+    av_frame_copy_props(outpic, inpic);
 
     /* Seed random generator for antibanding. */
     jran = LCG_SEED;
@@ -261,7 +261,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
         av_dlog(ctx, "out[%d]: %u\n", x, histeq->out_histogram[x]);
 #endif
 
-    avfilter_unref_bufferp(&inpic);
+    av_frame_free(&inpic);
     return ff_filter_frame(outlink, outpic);
 }
 
@@ -271,7 +271,6 @@ static const AVFilterPad histeq_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .config_props     = config_input,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_histogram.c b/libavfilter/vf_histogram.c
index 279e44aba1670725ffe561a9df6a191450c8e213..37e198625ce2f0d6f981b36e94b0509df39bcf7a 100644
--- a/libavfilter/vf_histogram.c
+++ b/libavfilter/vf_histogram.c
@@ -174,24 +174,23 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     HistogramContext *h   = inlink->dst->priv;
     AVFilterContext *ctx  = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     const uint8_t *src;
     uint8_t *dst;
     int i, j, k, l, ret;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
 
     out->pts = in->pts;
-    out->pos = in->pos;
 
     for (k = 0; k < h->ncomp; k++)
         for (i = 0; i < outlink->h; i++)
@@ -202,9 +201,9 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         for (k = 0; k < h->ncomp; k++) {
             int start = k * (h->level_height + h->scale_height) * h->display_mode;
 
-            for (i = 0; i < in->video->h; i++) {
+            for (i = 0; i < in->height; i++) {
                 src = in->data[k] + i * in->linesize[k];
-                for (j = 0; j < in->video->w; j++)
+                for (j = 0; j < in->width; j++)
                     h->histogram[src[j]]++;
             }
 
@@ -301,7 +300,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
     }
 
     ret = ff_filter_frame(outlink, out);
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     if (ret < 0)
         return ret;
     return 0;
@@ -320,7 +319,6 @@ static const AVFilterPad inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_input,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c
index 4381586bec3b31fdf8b22e1c459a84969516147d..5274956d8d10acbc5e6f6b197bf544f7230b4374 100644
--- a/libavfilter/vf_hqdn3d.c
+++ b/libavfilter/vf_hqdn3d.c
@@ -304,37 +304,38 @@ static int config_input(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     HQDN3DContext *hqdn3d = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
 
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int direct = 0, c;
 
-    if (in->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(in)) {
         direct = 1;
         out = in;
     } else {
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out) {
-            avfilter_unref_bufferp(&in);
+            av_frame_free(&in);
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(out, in);
+
+        av_frame_copy_props(out, in);
     }
 
     for (c = 0; c < 3; c++) {
         denoise(hqdn3d, in->data[c], out->data[c],
                 hqdn3d->line, &hqdn3d->frame_prev[c],
-                in->video->w >> (!!c * hqdn3d->hsub),
-                in->video->h >> (!!c * hqdn3d->vsub),
+                in->width  >> (!!c * hqdn3d->hsub),
+                in->height >> (!!c * hqdn3d->vsub),
                 in->linesize[c], out->linesize[c],
                 hqdn3d->coefs[c?2:0], hqdn3d->coefs[c?3:1]);
     }
 
     if (!direct)
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
 }
diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c
index 59fc62cef12bd7c3b717d5ffce7bfc021a1f7636..2e3a024cae24148a1f24cb4d3100fe68667758cf 100644
--- a/libavfilter/vf_hue.c
+++ b/libavfilter/vf_hue.c
@@ -276,18 +276,18 @@ static void process_chrominance(uint8_t *udst, uint8_t *vdst, const int dst_line
 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
 #define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
 {
     HueContext *hue = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpic;
+    AVFrame *outpic;
 
-    outpic = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!outpic) {
-        avfilter_unref_bufferp(&inpic);
+        av_frame_free(&inpic);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(outpic, inpic);
+    av_frame_copy_props(outpic, inpic);
 
     if (!hue->flat_syntax) {
         hue->var_values[VAR_T]   = TS2T(inpic->pts, inlink->time_base);
@@ -330,7 +330,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
                         inlink->w >> hue->hsub, inlink->h >> hue->vsub,
                         hue->hue_cos, hue->hue_sin);
 
-    avfilter_unref_bufferp(&inpic);
+    av_frame_free(&inpic);
     return ff_filter_frame(outlink, outpic);
 }
 
@@ -349,7 +349,6 @@ static const AVFilterPad hue_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_props,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c
index 5023630ecbfd19e9dced278e91794fe38ce01f02..0b1066346969d642ff6903472fcb0227be0241bc 100644
--- a/libavfilter/vf_idet.c
+++ b/libavfilter/vf_idet.c
@@ -47,9 +47,9 @@ typedef struct {
 
     uint8_t history[HIST_SIZE];
 
-    AVFilterBufferRef *cur;
-    AVFilterBufferRef *next;
-    AVFilterBufferRef *prev;
+    AVFrame *cur;
+    AVFrame *next;
+    AVFrame *prev;
     int (*filter_line)(const uint8_t *prev, const uint8_t *cur, const uint8_t *next, int w);
 
     const AVPixFmtDescriptor *csp;
@@ -113,8 +113,8 @@ static void filter(AVFilterContext *ctx)
     int match = 0;
 
     for (i = 0; i < idet->csp->nb_components; i++) {
-        int w = idet->cur->video->w;
-        int h = idet->cur->video->h;
+        int w = idet->cur->width;
+        int h = idet->cur->height;
         int refs = idet->cur->linesize[i];
 
         if (i && i<3) {
@@ -165,13 +165,13 @@ static void filter(AVFilterContext *ctx)
     }
 
     if      (idet->last_type == TFF){
-        idet->cur->video->top_field_first = 1;
-        idet->cur->video->interlaced = 1;
+        idet->cur->top_field_first = 1;
+        idet->cur->interlaced_frame = 1;
     }else if(idet->last_type == BFF){
-        idet->cur->video->top_field_first = 0;
-        idet->cur->video->interlaced = 1;
+        idet->cur->top_field_first = 0;
+        idet->cur->interlaced_frame = 1;
     }else if(idet->last_type == PROGRSSIVE){
-        idet->cur->video->interlaced = 0;
+        idet->cur->interlaced_frame = 0;
     }
 
     idet->prestat [           type] ++;
@@ -179,13 +179,13 @@ static void filter(AVFilterContext *ctx)
     av_log(ctx, AV_LOG_DEBUG, "Single frame:%s, Multi frame:%s\n", type2str(type), type2str(idet->last_type));
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *link, AVFrame *picref)
 {
     AVFilterContext *ctx = link->dst;
     IDETContext *idet = ctx->priv;
 
     if (idet->prev)
-        avfilter_unref_buffer(idet->prev);
+        av_frame_free(&idet->prev);
     idet->prev = idet->cur;
     idet->cur  = idet->next;
     idet->next = picref;
@@ -194,7 +194,7 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref)
         return 0;
 
     if (!idet->prev)
-        idet->prev = avfilter_ref_buffer(idet->cur, ~0);
+        idet->prev = av_frame_clone(idet->cur);
 
     if (!idet->csp)
         idet->csp = av_pix_fmt_desc_get(link->format);
@@ -203,7 +203,7 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref)
 
     filter(ctx);
 
-    return ff_filter_frame(ctx->outputs[0], avfilter_ref_buffer(idet->cur, ~0));
+    return ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->cur));
 }
 
 static int request_frame(AVFilterLink *link)
@@ -238,9 +238,9 @@ static av_cold void uninit(AVFilterContext *ctx)
            idet->poststat[UNDETERMINED]
     );
 
-    avfilter_unref_bufferp(&idet->prev);
-    avfilter_unref_bufferp(&idet->cur );
-    avfilter_unref_bufferp(&idet->next);
+    av_frame_free(&idet->prev);
+    av_frame_free(&idet->cur );
+    av_frame_free(&idet->next);
 }
 
 static int query_formats(AVFilterContext *ctx)
diff --git a/libavfilter/vf_il.c b/libavfilter/vf_il.c
index 44b5a3b264b18b84217cac486ab5c6a722692b34..29c277c31dbd21ecb40629825c1d67f4d4c4382e 100644
--- a/libavfilter/vf_il.c
+++ b/libavfilter/vf_il.c
@@ -160,19 +160,19 @@ static void interleave(uint8_t *dst, uint8_t *src, int w, int h,
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     IlContext *il = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int ret, comp;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&inpicref);
+        av_frame_free(&inpicref);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, inpicref);
+    av_frame_copy_props(out, inpicref);
 
     interleave(out->data[0], inpicref->data[0],
                il->linesize[0], inlink->h,
@@ -195,7 +195,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
     }
 
     ret = ff_filter_frame(outlink, out);
-    avfilter_unref_bufferp(&inpicref);
+    av_frame_free(&inpicref);
     return ret;
 }
 
diff --git a/libavfilter/vf_kerndeint.c b/libavfilter/vf_kerndeint.c
index 9b77e09e585fd2f03b3a93e59d235b97e1800ea4..7e89648a38f0ae30ecdf27a9e8fa593cb2c4c72e 100644
--- a/libavfilter/vf_kerndeint.c
+++ b/libavfilter/vf_kerndeint.c
@@ -116,11 +116,11 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
 {
     KerndeintContext *kerndeint = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpic;
+    AVFrame *outpic;
     const uint8_t *prvp;   ///< Previous field's pixel line number n
     const uint8_t *prvpp;  ///< Previous field's pixel line number (n - 1)
     const uint8_t *prvpn;  ///< Previous field's pixel line number (n + 1)
@@ -154,13 +154,13 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
 
     const int is_packed_rgb = kerndeint->is_packed_rgb;
 
-    outpic = ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN, outlink->w, outlink->h);
+    outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!outpic) {
-        avfilter_unref_bufferp(&inpic);
+        av_frame_free(&inpic);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(outpic, inpic);
-    outpic->video->interlaced = 0;
+    av_frame_copy_props(outpic, inpic);
+    outpic->interlaced_frame = 0;
 
     for (plane = 0; inpic->data[plane] && plane < 4; plane++) {
         h = plane == 0 ? inlink->h : inlink->h >> kerndeint->vsub;
@@ -295,7 +295,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
         av_image_copy_plane(dstp, psrc_linesize, srcp, src_linesize, bwidth, h);
     }
 
-    avfilter_unref_buffer(inpic);
+    av_frame_free(&inpic);
     return ff_filter_frame(outlink, outpic);
 }
 
@@ -305,7 +305,6 @@ static const AVFilterPad kerndeint_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_props,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c
index 2d26b380378860caccb8462027e1717641bc398b..7174ccc34a4b5885d8da06e8243309ff78486c56 100644
--- a/libavfilter/vf_libopencv.c
+++ b/libavfilter/vf_libopencv.c
@@ -35,7 +35,7 @@
 #include "internal.h"
 #include "video.h"
 
-static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *picref, enum AVPixelFormat pixfmt)
+static void fill_iplimage_from_frame(IplImage *img, const AVFrame *frame, enum AVPixelFormat pixfmt)
 {
     IplImage *tmpimg;
     int depth, channels_nb;
@@ -45,18 +45,18 @@ static void fill_iplimage_from_picref(IplImage *img, const AVFilterBufferRef *pi
     else if (pixfmt == AV_PIX_FMT_BGR24) { depth = IPL_DEPTH_8U;  channels_nb = 3; }
     else return;
 
-    tmpimg = cvCreateImageHeader((CvSize){picref->video->w, picref->video->h}, depth, channels_nb);
+    tmpimg = cvCreateImageHeader((CvSize){frame->width, frame->height}, depth, channels_nb);
     *img = *tmpimg;
-    img->imageData = img->imageDataOrigin = picref->data[0];
+    img->imageData = img->imageDataOrigin = frame->data[0];
     img->dataOrder = IPL_DATA_ORDER_PIXEL;
     img->origin    = IPL_ORIGIN_TL;
-    img->widthStep = picref->linesize[0];
+    img->widthStep = frame->linesize[0];
 }
 
-static void fill_picref_from_iplimage(AVFilterBufferRef *picref, const IplImage *img, enum AVPixelFormat pixfmt)
+static void fill_frame_from_iplimage(AVFrame *frame, const IplImage *img, enum AVPixelFormat pixfmt)
 {
-    picref->linesize[0] = img->widthStep;
-    picref->data[0]     = img->imageData;
+    frame->linesize[0] = img->widthStep;
+    frame->data[0]     = img->imageData;
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -351,27 +351,27 @@ static av_cold void uninit(AVFilterContext *ctx)
     memset(ocv, 0, sizeof(*ocv));
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     OCVContext *ocv = ctx->priv;
     AVFilterLink *outlink= inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     IplImage inimg, outimg;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
-    fill_iplimage_from_picref(&inimg , in , inlink->format);
-    fill_iplimage_from_picref(&outimg, out, inlink->format);
+    fill_iplimage_from_frame(&inimg , in , inlink->format);
+    fill_iplimage_from_frame(&outimg, out, inlink->format);
     ocv->end_frame_filter(ctx, &inimg, &outimg);
-    fill_picref_from_iplimage(out, &outimg, inlink->format);
+    fill_frame_from_iplimage(out, &outimg, inlink->format);
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
 
     return ff_filter_frame(outlink, out);
 }
@@ -381,7 +381,6 @@ static const AVFilterPad avfilter_vf_ocv_inputs[] = {
         .name       = "default",
         .type       = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
-        .min_perms  = AV_PERM_READ
     },
     { NULL }
 };
diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c
index bdfe712cf460d7a4474b84dc73bfd0d0701d961e..1738560b5d1d6eb0f8729ffdd430149087183316 100644
--- a/libavfilter/vf_lut.c
+++ b/libavfilter/vf_lut.c
@@ -253,28 +253,28 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     AVFilterContext *ctx = inlink->dst;
     LutContext *lut = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     uint8_t *inrow, *outrow, *inrow0, *outrow0;
     int i, j, plane;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     if (lut->is_rgb) {
         /* packed */
         inrow0  = in ->data[0];
         outrow0 = out->data[0];
 
-        for (i = 0; i < in->video->h; i ++) {
+        for (i = 0; i < in->height; i ++) {
             int w = inlink->w;
             const uint8_t (*tab)[256] = (const uint8_t (*)[256])lut->lut;
             inrow  = inrow0;
@@ -305,7 +305,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
             inrow  = in ->data[plane];
             outrow = out->data[plane];
 
-            for (i = 0; i < (in->video->h + (1<<vsub) - 1)>>vsub; i ++) {
+            for (i = 0; i < (in->height + (1<<vsub) - 1)>>vsub; i ++) {
                 const uint8_t *tab = lut->lut[plane];
                 int w = (inlink->w + (1<<hsub) - 1)>>hsub;
                 for (j = 0; j < w; j++)
@@ -316,7 +316,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         }
     }
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -325,7 +325,7 @@ static const AVFilterPad inputs[] = {
       .type            = AVMEDIA_TYPE_VIDEO,
       .filter_frame    = filter_frame,
       .config_props    = config_props,
-      .min_perms       = AV_PERM_READ, },
+    },
     { .name = NULL}
 };
 static const AVFilterPad outputs[] = {
diff --git a/libavfilter/vf_mp.c b/libavfilter/vf_mp.c
index 4321d92acf637a2fad01ca7a0ecd197c7a6cda32..0a00ec9bb814f7a68862837b5304c7326c131633 100644
--- a/libavfilter/vf_mp.c
+++ b/libavfilter/vf_mp.c
@@ -536,45 +536,38 @@ mp_image_t* ff_vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgty
   return mpi;
 }
 
+static void dummy_free(void *opaque, uint8_t *data){}
 
 int ff_vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
     MPContext *m= (void*)vf;
     AVFilterLink *outlink     = m->avfctx->outputs[0];
-    AVFilterBuffer    *pic    = av_mallocz(sizeof(AVFilterBuffer));
-    AVFilterBufferRef *picref = av_mallocz(sizeof(AVFilterBufferRef));
+    AVFrame *picref = av_frame_alloc();
     int i;
 
     av_assert0(vf->next);
 
     av_log(m->avfctx, AV_LOG_DEBUG, "ff_vf_next_put_image\n");
 
-    if (!pic || !picref)
+    if (!picref)
         goto fail;
 
-    picref->buf = pic;
-    picref->buf->free= (void*)av_free;
-    if (!(picref->video = av_mallocz(sizeof(AVFilterBufferRefVideoProps))))
-        goto fail;
-
-    pic->w = picref->video->w = mpi->w;
-    pic->h = picref->video->h = mpi->h;
-
-    /* make sure the buffer gets read permission or it's useless for output */
-    picref->perms = AV_PERM_READ | AV_PERM_REUSE2;
-//    av_assert0(mpi->flags&MP_IMGFLAG_READABLE);
-    if(!(mpi->flags&MP_IMGFLAG_PRESERVE))
-        picref->perms |= AV_PERM_WRITE;
+    picref->width  = mpi->w;
+    picref->height = mpi->h;
 
-    pic->refcount = 1;
     picref->type = AVMEDIA_TYPE_VIDEO;
 
     for(i=0; conversion_map[i].fmt && mpi->imgfmt != conversion_map[i].fmt; i++);
-    pic->format = picref->format = conversion_map[i].pix_fmt;
+    picref->format = conversion_map[i].pix_fmt;
 
-    memcpy(pic->data,        mpi->planes,   FFMIN(sizeof(pic->data)    , sizeof(mpi->planes)));
-    memcpy(pic->linesize,    mpi->stride,   FFMIN(sizeof(pic->linesize), sizeof(mpi->stride)));
-    memcpy(picref->data,     pic->data,     sizeof(picref->data));
-    memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
+    memcpy(picref->linesize, mpi->stride, FFMIN(sizeof(picref->linesize), sizeof(mpi->stride)));
+
+    for(i=0; i<4 && mpi->stride[i]; i++){
+        picref->buf[i] = av_buffer_create(mpi->planes[i], mpi->stride[i], dummy_free, NULL,
+                                          (mpi->flags & MP_IMGFLAG_PRESERVE) ? AV_BUFFER_FLAG_READONLY : 0);
+        if (!picref->buf[i])
+            goto fail;
+        picref->data[i] = picref->buf[i]->data;
+    }
 
     if(pts != MP_NOPTS_VALUE)
         picref->pts= pts * av_q2d(outlink->time_base);
@@ -584,10 +577,7 @@ int ff_vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
 
     return 1;
 fail:
-    if (picref && picref->video)
-        av_free(picref->video);
-    av_free(picref);
-    av_free(pic);
+    av_frame_free(&picref);
     return 0;
 }
 
@@ -793,12 +783,12 @@ static int request_frame(AVFilterLink *outlink)
     return ret;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
 {
     MPContext *m = inlink->dst->priv;
     int i;
     double pts= MP_NOPTS_VALUE;
-    mp_image_t* mpi = ff_new_mp_image(inpic->video->w, inpic->video->h);
+    mp_image_t* mpi = ff_new_mp_image(inpic->width, inpic->height);
 
     if(inpic->pts != AV_NOPTS_VALUE)
         pts= inpic->pts / av_q2d(inlink->time_base);
@@ -813,12 +803,12 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
 
     // mpi->flags|=MP_IMGFLAG_ALLOCATED; ?
     mpi->flags |= MP_IMGFLAG_READABLE;
-    if(!(inpic->perms & AV_PERM_WRITE))
+    if(!av_frame_is_writable(inpic))
         mpi->flags |= MP_IMGFLAG_PRESERVE;
     if(m->vf.put_image(&m->vf, mpi, pts) == 0){
         av_log(m->avfctx, AV_LOG_DEBUG, "put_image() says skip\n");
     }else{
-        avfilter_unref_buffer(inpic);
+        av_frame_free(&inpic);
     }
     ff_free_mp_image(mpi);
     return 0;
@@ -830,7 +820,6 @@ static const AVFilterPad mp_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_inprops,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
index d3e443b65b49e908793a0c037be405f873074131..e80f46166338b4331b8d61663c3360a2aa7be6ee 100644
--- a/libavfilter/vf_noise.c
+++ b/libavfilter/vf_noise.c
@@ -298,22 +298,22 @@ static void noise(uint8_t *dst, const uint8_t *src,
         n->param[comp].shiftptr = 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     NoiseContext *n = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int ret, i;
 
-    if (inpicref->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(inpicref)) {
         out = inpicref;
     } else {
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out) {
-            avfilter_unref_bufferp(&inpicref);
+            av_frame_free(&inpicref);
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(out, inpicref);
+        av_frame_copy_props(out, inpicref);
     }
 
     for (i = 0; i < n->nb_planes; i++)
@@ -322,7 +322,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
 
     ret = ff_filter_frame(outlink, out);
     if (inpicref != out)
-        avfilter_unref_buffer(inpicref);
+        av_frame_free(&inpicref);
     return ret;
 }
 
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index 1a76ecccd74abc1902efbbead575d5d53ff401d3..313fef1533fd897eb077a5592ad4f8a7349ad2f3 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -85,7 +85,7 @@ typedef struct {
     uint8_t overlay_has_alpha;
     enum OverlayFormat { OVERLAY_FORMAT_YUV420, OVERLAY_FORMAT_YUV444, OVERLAY_FORMAT_RGB, OVERLAY_FORMAT_NB} format;
 
-    AVFilterBufferRef *overpicref;
+    AVFrame *overpicref;
     struct FFBufQueue queue_main;
     struct FFBufQueue queue_over;
 
@@ -143,7 +143,7 @@ static av_cold void uninit(AVFilterContext *ctx)
 
     av_opt_free(over);
 
-    avfilter_unref_bufferp(&over->overpicref);
+    av_frame_free(&over->overpicref);
     ff_bufqueue_discard_all(&over->queue_main);
     ff_bufqueue_discard_all(&over->queue_over);
 }
@@ -316,15 +316,15 @@ static int config_output(AVFilterLink *outlink)
  * Blend image in src to destination buffer dst at position (x, y).
  */
 static void blend_image(AVFilterContext *ctx,
-                        AVFilterBufferRef *dst, AVFilterBufferRef *src,
+                        AVFrame *dst, AVFrame *src,
                         int x, int y)
 {
     OverlayContext *over = ctx->priv;
     int i, imax, j, jmax, k, kmax;
-    const int src_w = src->video->w;
-    const int src_h = src->video->h;
-    const int dst_w = dst->video->w;
-    const int dst_h = dst->video->h;
+    const int src_w = src->width;
+    const int src_h = src->height;
+    const int dst_w = dst->width;
+    const int dst_h = dst->height;
 
     if (x >= dst_w || x+dst_w  < 0 ||
         y >= dst_h || y+dst_h < 0)
@@ -503,11 +503,11 @@ static void blend_image(AVFilterContext *ctx,
     }
 }
 
-static int try_filter_frame(AVFilterContext *ctx, AVFilterBufferRef *mainpic)
+static int try_filter_frame(AVFilterContext *ctx, AVFrame *mainpic)
 {
     OverlayContext *over = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *next_overpic;
+    AVFrame *next_overpic;
     int ret;
 
     /* Discard obsolete overlay frames: if there is a next overlay frame with pts
@@ -518,7 +518,7 @@ static int try_filter_frame(AVFilterContext *ctx, AVFilterBufferRef *mainpic)
                                            mainpic->pts     , ctx->inputs[MAIN]->time_base) > 0)
             break;
         ff_bufqueue_get(&over->queue_over);
-        avfilter_unref_buffer(over->overpicref);
+        av_frame_free(&over->overpicref);
         over->overpicref = next_overpic;
     }
 
@@ -549,7 +549,7 @@ static int try_filter_frame(AVFilterContext *ctx, AVFilterBufferRef *mainpic)
 static int try_filter_next_frame(AVFilterContext *ctx)
 {
     OverlayContext *over = ctx->priv;
-    AVFilterBufferRef *next_mainpic = ff_bufqueue_peek(&over->queue_main, 0);
+    AVFrame *next_mainpic = ff_bufqueue_peek(&over->queue_main, 0);
     int ret;
 
     if (!next_mainpic)
@@ -568,7 +568,7 @@ static int flush_frames(AVFilterContext *ctx)
     return ret == AVERROR(EAGAIN) ? 0 : ret;
 }
 
-static int filter_frame_main(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame_main(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterContext *ctx = inlink->dst;
     OverlayContext *over = ctx->priv;
@@ -589,7 +589,7 @@ static int filter_frame_main(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
     return 0;
 }
 
-static int filter_frame_over(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame_over(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterContext *ctx = inlink->dst;
     OverlayContext *over = ctx->priv;
@@ -639,14 +639,13 @@ static const AVFilterPad avfilter_vf_overlay_inputs[] = {
         .get_video_buffer = ff_null_get_video_buffer,
         .config_props = config_input_main,
         .filter_frame = filter_frame_main,
-        .min_perms    = AV_PERM_READ | AV_PERM_WRITE | AV_PERM_PRESERVE,
+        .needs_writable = 1,
     },
     {
         .name         = "overlay",
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input_overlay,
         .filter_frame = filter_frame_over,
-        .min_perms    = AV_PERM_READ | AV_PERM_PRESERVE,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c
index 5c146f208f375ceff1879725d6386e37790b7e1f..86fd683ce2b3a1309cb8c301cc534a6af4bc8042 100644
--- a/libavfilter/vf_pad.c
+++ b/libavfilter/vf_pad.c
@@ -238,98 +238,126 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
 {
     PadContext *pad = inlink->dst->priv;
-    int align = (perms&AV_PERM_ALIGN) ? AVFILTER_ALIGN : 1;
 
-    AVFilterBufferRef *picref = ff_get_video_buffer(inlink->dst->outputs[0], perms,
-                                                    w + (pad->w - pad->in_w) + 4*align,
-                                                    h + (pad->h - pad->in_h));
+    AVFrame *frame = ff_get_video_buffer(inlink->dst->outputs[0],
+                                         w + (pad->w - pad->in_w),
+                                         h + (pad->h - pad->in_h));
     int plane;
 
-    if (!picref)
+    if (!frame)
         return NULL;
 
-    picref->video->w = w;
-    picref->video->h = h;
+    frame->width  = w;
+    frame->height = h;
 
-    for (plane = 0; plane < 4 && picref->data[plane]; plane++)
-        picref->data[plane] += FFALIGN(pad->x >> pad->draw.hsub[plane], align) * pad->draw.pixelstep[plane] +
-                                      (pad->y >> pad->draw.vsub[plane])        * picref->linesize[plane];
+    for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
+        int hsub = pad->draw.hsub[plane];
+        int vsub = pad->draw.vsub[plane];
+        frame->data[plane] += (pad->x >> hsub) * pad->draw.pixelstep[plane] +
+                              (pad->y >> vsub) * frame->linesize[plane];
+    }
 
-    return picref;
+    return frame;
 }
 
-static int does_clip(PadContext *pad, AVFilterBufferRef *outpicref, int plane, int hsub, int vsub, int x, int y)
+/* check whether each plane in this buffer can be padded without copying */
+static int buffer_needs_copy(PadContext *s, AVFrame *frame, AVBufferRef *buf)
 {
-    int64_t x_in_buf, y_in_buf;
+    int planes[4] = { -1, -1, -1, -1}, *p = planes;
+    int i, j;
 
-    x_in_buf =  outpicref->data[plane] - outpicref->buf->data[plane]
-             +  (x >> hsub) * pad->draw.pixelstep[plane]
-             +  (y >> vsub) * outpicref->linesize[plane];
+    /* get all planes in this buffer */
+    for (i = 0; i < FF_ARRAY_ELEMS(planes) && frame->data[i]; i++) {
+        if (av_frame_get_plane_buffer(frame, i) == buf)
+            *p++ = i;
+    }
 
-    if(x_in_buf < 0 || x_in_buf % pad->draw.pixelstep[plane])
-        return 1;
-    x_in_buf /= pad->draw.pixelstep[plane];
+    /* for each plane in this buffer, check that it can be padded without
+     * going over buffer bounds or other planes */
+    for (i = 0; i < FF_ARRAY_ELEMS(planes) && planes[i] >= 0; i++) {
+        int hsub = s->draw.hsub[planes[i]];
+        int vsub = s->draw.vsub[planes[i]];
+
+        uint8_t *start = frame->data[planes[i]];
+        uint8_t *end   = start + (frame->height >> hsub) *
+                                 frame->linesize[planes[i]];
+
+        /* amount of free space needed before the start and after the end
+         * of the plane */
+        ptrdiff_t req_start = (s->x >> hsub) * s->draw.pixelstep[planes[i]] +
+                              (s->y >> vsub) * frame->linesize[planes[i]];
+        ptrdiff_t req_end   = ((s->w - s->x - frame->width) >> hsub) *
+                              s->draw.pixelstep[planes[i]] +
+                              (s->y >> vsub) * frame->linesize[planes[i]];
+
+        if (frame->linesize[planes[i]] < (s->w >> hsub) * s->draw.pixelstep[planes[i]])
+            return 1;
+        if (start - buf->data < req_start ||
+            (buf->data + buf->size) - end < req_end)
+            return 1;
+
+#define SIGN(x) ((x) > 0 ? 1 : -1)
+        for (j = 0; j < FF_ARRAY_ELEMS(planes) & planes[j] >= 0; j++) {
+            int hsub1 = s->draw.hsub[planes[j]];
+            uint8_t *start1 = frame->data[planes[j]];
+            uint8_t *end1   = start1 + (frame->height >> hsub1) *
+                                       frame->linesize[planes[j]];
+            if (i == j)
+                continue;
+
+            if (SIGN(start - end1) != SIGN(start - end1 - req_start) ||
+                SIGN(end - start1) != SIGN(end - start1 + req_end))
+                return 1;
+        }
+    }
 
-    av_assert0(outpicref->buf->linesize[plane]>0); //while reference can use negative linesize the main buffer should not
+    return 0;
+}
 
-    y_in_buf = x_in_buf / outpicref->buf->linesize[plane];
-    x_in_buf %= outpicref->buf->linesize[plane];
+static int frame_needs_copy(PadContext *s, AVFrame *frame)
+{
+    int i;
 
-    if(   y_in_buf<<vsub >= outpicref->buf->h
-       || x_in_buf<<hsub >= outpicref->buf->w)
+    if (!av_frame_is_writable(frame))
         return 1;
+
+    for (i = 0; i < 4 && frame->buf[i]; i++)
+        if (buffer_needs_copy(s, frame, frame->buf[i]))
+            return 1;
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     PadContext *pad = inlink->dst->priv;
-    AVFilterBufferRef *out = avfilter_ref_buffer(in, ~0);
-    int plane, needs_copy;
-
-    if (!out) {
-        avfilter_unref_bufferp(&in);
-        return AVERROR(ENOMEM);
-    }
-
-    for (plane = 0; plane < 4 && out->data[plane] && pad->draw.pixelstep[plane]; plane++) {
-        int hsub = pad->draw.hsub[plane];
-        int vsub = pad->draw.vsub[plane];
-
-        av_assert0(out->buf->w > 0 && out->buf->h > 0);
-
-        if (out->format != out->buf->format) //unsupported currently
-            break;
+    AVFrame *out;
+    int needs_copy = frame_needs_copy(pad, in);
 
-        out->data[plane] -= (pad->x  >> hsub) * pad->draw.pixelstep[plane] +
-                            (pad->y  >> vsub) * out->linesize[plane];
-
-        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;
-    }
-    needs_copy = plane < 4 && out->data[plane] || !(out->perms & AV_PERM_WRITE);
     if (needs_copy) {
         av_log(inlink->dst, AV_LOG_DEBUG, "Direct padding impossible allocating new frame\n");
-        avfilter_unref_buffer(out);
-        out = ff_get_video_buffer(inlink->dst->outputs[0], AV_PERM_WRITE | AV_PERM_NEG_LINESIZES,
+        out = ff_get_video_buffer(inlink->dst->outputs[0],
                                   FFMAX(inlink->w, pad->w),
                                   FFMAX(inlink->h, pad->h));
         if (!out) {
-            avfilter_unref_bufferp(&in);
+            av_frame_free(&in);
             return AVERROR(ENOMEM);
         }
 
-        avfilter_copy_buffer_ref_props(out, in);
-    }
+        av_frame_copy_props(out, in);
+    } else {
+        int i;
 
-    out->video->w = pad->w;
-    out->video->h = pad->h;
+        out = in;
+        for (i = 0; i < 4 && out->data[i]; i++) {
+            int hsub = pad->draw.hsub[i];
+            int vsub = pad->draw.vsub[i];
+            out->data[i] -= (pad->x >> hsub) * pad->draw.pixelstep[i] +
+                            (pad->y >> vsub) * out->linesize[i];
+        }
+    }
 
     /* top bar */
     if (pad->y) {
@@ -347,20 +375,24 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
 
     /* left border */
     ff_fill_rectangle(&pad->draw, &pad->color, out->data, out->linesize,
-                      0, pad->y, pad->x, in->video->h);
+                      0, pad->y, pad->x, in->height);
 
     if (needs_copy) {
         ff_copy_rectangle2(&pad->draw,
                           out->data, out->linesize, in->data, in->linesize,
-                          pad->x, pad->y, 0, 0, in->video->w, in->video->h);
+                          pad->x, pad->y, 0, 0, in->width, in->height);
     }
 
     /* right border */
     ff_fill_rectangle(&pad->draw, &pad->color, out->data, out->linesize,
                       pad->x + pad->in_w, pad->y, pad->w - pad->x - pad->in_w,
-                      in->video->h);
+                      in->height);
+
+    out->width  = pad->w;
+    out->height = pad->h;
 
-    avfilter_unref_bufferp(&in);
+    if (in != out)
+        av_frame_free(&in);
     return ff_filter_frame(inlink->dst->outputs[0], out);
 }
 
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index 6ac03d9706db03f07503c957db8fd42b3e138463..42afc639c3a6c1cd9acf324dcafffd68da4d1d80 100644
--- a/libavfilter/vf_pixdesctest.c
+++ b/libavfilter/vf_pixdesctest.c
@@ -52,21 +52,20 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     PixdescTestContext *priv = inlink->dst->priv;
     AVFilterLink *outlink    = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int i, c, w = inlink->w, h = inlink->h;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE,
-                              outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
 
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_props(out, in);
 
     for (i = 0; i < 4; i++) {
         int h = outlink->h;
@@ -102,7 +101,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         }
     }
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -112,7 +111,6 @@ static const AVFilterPad avfilter_vf_pixdesctest_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_props,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c
index bde5ebf3ceebacd7732165a6a909c8036023515d..b6cdbe68657638419be42ee7c931c3024882d751 100644
--- a/libavfilter/vf_pp.c
+++ b/libavfilter/vf_pp.c
@@ -100,32 +100,32 @@ static int pp_config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static int pp_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inbuf)
+static int pp_filter_frame(AVFilterLink *inlink, AVFrame *inbuf)
 {
     AVFilterContext *ctx = inlink->dst;
     PPFilterContext *pp = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
     const int aligned_w = FFALIGN(outlink->w, 8);
     const int aligned_h = FFALIGN(outlink->h, 8);
-    AVFilterBufferRef *outbuf;
+    AVFrame *outbuf;
 
-    outbuf = ff_get_video_buffer(outlink, AV_PERM_WRITE, aligned_w, aligned_h);
+    outbuf = ff_get_video_buffer(outlink, aligned_w, aligned_h);
     if (!outbuf) {
-        avfilter_unref_buffer(inbuf);
+        av_frame_free(&inbuf);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(outbuf, inbuf);
+    av_frame_copy_props(outbuf, inbuf);
 
     pp_postprocess((const uint8_t **)inbuf->data, inbuf->linesize,
                    outbuf->data,                 outbuf->linesize,
                    aligned_w, outlink->h,
-                   outbuf->video->qp_table,
-                   outbuf->video->qp_table_linesize,
+                   outbuf->qscale_table,
+                   outbuf->qstride,
                    pp->modes[pp->mode_id],
                    pp->pp_ctx,
-                   outbuf->video->pict_type);
+                   outbuf->pict_type);
 
-    avfilter_unref_buffer(inbuf);
+    av_frame_free(&inbuf);
     return ff_filter_frame(outlink, outbuf);
 }
 
@@ -146,7 +146,6 @@ static const AVFilterPad pp_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = pp_config_props,
         .filter_frame = pp_filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_removelogo.c b/libavfilter/vf_removelogo.c
index ddaf9ef4ca44f901acfb6a3338c6c5ac2cc09619..e3da1970bae627ac3d80a727947275bd4ef0ba18 100644
--- a/libavfilter/vf_removelogo.c
+++ b/libavfilter/vf_removelogo.c
@@ -473,23 +473,23 @@ static void blur_image(int ***mask,
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     RemovelogoContext *removelogo = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpicref;
+    AVFrame *outpicref;
     int direct = 0;
 
-    if (inpicref->perms & AV_PERM_WRITE) {
+    if (av_frame_is_writable(inpicref)) {
         direct = 1;
         outpicref = inpicref;
     } else {
-        outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!outpicref) {
-            avfilter_unref_bufferp(&inpicref);
+            av_frame_free(&inpicref);
             return AVERROR(ENOMEM);
         }
-        avfilter_copy_buffer_ref_props(outpicref, inpicref);
+        av_frame_copy_props(outpicref, inpicref);
     }
 
     blur_image(removelogo->mask,
@@ -509,7 +509,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
                inlink->w/2, inlink->h/2, direct, &removelogo->half_mask_bbox);
 
     if (!direct)
-        avfilter_unref_bufferp(&inpicref);
+        av_frame_free(&inpicref);
 
     return ff_filter_frame(outlink, outpicref);
 }
@@ -543,7 +543,6 @@ static const AVFilterPad removelogo_inputs[] = {
         .get_video_buffer = ff_null_get_video_buffer,
         .config_props     = config_props_input,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index f6e79ff111794497a7d271a985a06e45441c5c90..4cc6aab5b879fb81a1800c18fae0d7e6ba0e9652 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -329,7 +329,7 @@ fail:
     return ret;
 }
 
-static int scale_slice(AVFilterLink *link, AVFilterBufferRef *out_buf, AVFilterBufferRef *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
+static int scale_slice(AVFilterLink *link, AVFrame *out_buf, AVFrame *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
 {
     ScaleContext *scale = link->dst->priv;
     const uint8_t *in[4];
@@ -353,17 +353,17 @@ static int scale_slice(AVFilterLink *link, AVFilterBufferRef *out_buf, AVFilterB
                          out,out_stride);
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *link, AVFrame *in)
 {
     ScaleContext *scale = link->dst->priv;
     AVFilterLink *outlink = link->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
     char buf[32];
 
-    if(   in->video->w != link->w
-       || in->video->h != link->h
-       || in->format   != link->format) {
+    if(   in->width  != link->w
+       || in->height != link->h
+       || in->format != link->format) {
         int ret;
         snprintf(buf, sizeof(buf)-1, "%d", outlink->w);
         av_opt_set(scale, "w", buf, 0);
@@ -371,8 +371,8 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
         av_opt_set(scale, "h", buf, 0);
 
         link->dst->inputs[0]->format = in->format;
-        link->dst->inputs[0]->w      = in->video->w;
-        link->dst->inputs[0]->h      = in->video->h;
+        link->dst->inputs[0]->w      = in->width;
+        link->dst->inputs[0]->h      = in->height;
 
         if ((ret = config_props(outlink)) < 0)
             return ret;
@@ -384,32 +384,32 @@ static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
     scale->hsub = desc->log2_chroma_w;
     scale->vsub = desc->log2_chroma_h;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
 
-    avfilter_copy_buffer_ref_props(out, in);
-    out->video->w = outlink->w;
-    out->video->h = outlink->h;
+    av_frame_copy_props(out, in);
+    out->width  = outlink->w;
+    out->height = outlink->h;
 
     if(scale->output_is_pal)
         avpriv_set_systematic_pal2((uint32_t*)out->data[1], outlink->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink->format);
 
-    av_reduce(&out->video->sample_aspect_ratio.num, &out->video->sample_aspect_ratio.den,
-              (int64_t)in->video->sample_aspect_ratio.num * outlink->h * link->w,
-              (int64_t)in->video->sample_aspect_ratio.den * outlink->w * link->h,
+    av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
+              (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
+              (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
               INT_MAX);
 
-    if(scale->interlaced>0 || (scale->interlaced<0 && in->video->interlaced)){
+    if(scale->interlaced>0 || (scale->interlaced<0 && in->interlaced_frame)){
         scale_slice(link, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0);
         scale_slice(link, out, in, scale->isws[1], 0,  link->h   /2, 2, 1);
     }else{
         scale_slice(link, out, in, scale->sws, 0, link->h, 1, 0);
     }
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -418,7 +418,6 @@ static const AVFilterPad avfilter_vf_scale_inputs[] = {
         .name        = "default",
         .type        = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
-        .min_perms   = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_setfield.c b/libavfilter/vf_setfield.c
index 43949fa5691e27ab74f79b7b76888c26d0e7c914..bb97a8419ed36fdb5db70f1091cce1680b510e04 100644
--- a/libavfilter/vf_setfield.c
+++ b/libavfilter/vf_setfield.c
@@ -71,15 +71,15 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_opt_free(setfield);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
     SetFieldContext *setfield = inlink->dst->priv;
 
     if (setfield->mode == MODE_PROG) {
-        picref->video->interlaced = 0;
+        picref->interlaced_frame = 0;
     } else if (setfield->mode != MODE_AUTO) {
-        picref->video->interlaced = 1;
-        picref->video->top_field_first = setfield->mode;
+        picref->interlaced_frame = 1;
+        picref->top_field_first = setfield->mode;
     }
     return ff_filter_frame(inlink->dst->outputs[0], picref);
 }
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index f91721d2781ada9c4bae38968ae3acf219b863a6..6c412e5abc2f7237e71057f42d01c1d65c7f6d48 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -42,7 +42,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     AVFilterContext *ctx = inlink->dst;
     ShowInfoContext *showinfo = ctx->priv;
@@ -51,7 +51,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
     int i, plane, vsub = desc->log2_chroma_h;
 
     for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
-        int64_t linesize = av_image_get_linesize(frame->format, frame->video->w, plane);
+        int64_t linesize = av_image_get_linesize(frame->format, frame->width, plane);
         uint8_t *data = frame->data[plane];
         int h = plane == 1 || plane == 2 ? inlink->h >> vsub : inlink->h;
 
@@ -70,14 +70,14 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
            "fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c "
            "checksum:%08X plane_checksum:[%08X",
            showinfo->frame,
-           av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base), frame->pos,
+           av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base), av_frame_get_pkt_pos(frame),
            desc->name,
-           frame->video->sample_aspect_ratio.num, frame->video->sample_aspect_ratio.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),
+           frame->sample_aspect_ratio.num, frame->sample_aspect_ratio.den,
+           frame->width, frame->height,
+           !frame->interlaced_frame ? 'P' :         /* Progressive  */
+           frame->top_field_first   ? 'T' : 'B',    /* Top / Bottom */
+           frame->key_frame,
+           av_get_picture_type_char(frame->pict_type),
            checksum, plane_checksum[0]);
 
     for (plane = 1; plane < 4 && frame->data[plane]; plane++)
@@ -94,7 +94,6 @@ static const AVFilterPad avfilter_vf_showinfo_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c
index 54ab2094fca4718c9d9b1844a0cbced6d1611bf9..ccbd22b41ebe0ae016ef0851ff11c5f43adb61c3 100644
--- a/libavfilter/vf_smartblur.c
+++ b/libavfilter/vf_smartblur.c
@@ -246,20 +246,20 @@ static void blur(uint8_t       *dst, const int dst_linesize,
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
 {
     SmartblurContext  *sblur  = inlink->dst->priv;
     AVFilterLink *outlink     = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpic;
+    AVFrame *outpic;
     int cw = inlink->w >> sblur->hsub;
     int ch = inlink->h >> sblur->vsub;
 
-    outpic = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!outpic) {
-        avfilter_unref_bufferp(&inpic);
+        av_frame_free(&inpic);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(outpic, inpic);
+    av_frame_copy_props(outpic, inpic);
 
     blur(outpic->data[0], outpic->linesize[0],
          inpic->data[0],  inpic->linesize[0],
@@ -277,7 +277,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpic)
              sblur->chroma.filter_context);
     }
 
-    avfilter_unref_bufferp(&inpic);
+    av_frame_free(&inpic);
     return ff_filter_frame(outlink, outpic);
 }
 
diff --git a/libavfilter/vf_stereo3d.c b/libavfilter/vf_stereo3d.c
index 37579157112e308ffe7573d70106b38208f6adfb..86aa29ff31fb83c681e45cf2c23460606b640e5d 100644
--- a/libavfilter/vf_stereo3d.c
+++ b/libavfilter/vf_stereo3d.c
@@ -339,24 +339,22 @@ static inline uint8_t ana_convert(const int *coeff, uint8_t *left, uint8_t *righ
     return av_clip_uint8(sum >> 16);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterContext *ctx  = inlink->dst;
     Stereo3DContext *s = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int out_off_left, out_off_right;
     int in_off_left, in_off_right;
     int ret;
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&inpicref);
+        av_frame_free(&inpicref);
         return AVERROR(ENOMEM);
     }
-
-    out->pts = inpicref->pts;
-    out->pos = inpicref->pos;
+    av_frame_copy_props(out, inpicref);
 
     in_off_left   = s->in.row_left  * inpicref->linesize[0] + s->in.off_left;
     in_off_right  = s->in.row_right * inpicref->linesize[0] + s->in.off_right;
@@ -432,7 +430,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
     }
 
     ret = ff_filter_frame(outlink, out);
-    avfilter_unref_bufferp(&inpicref);
+    av_frame_free(&inpicref);
     if (ret < 0)
         return ret;
     return 0;
@@ -451,7 +449,6 @@ static const AVFilterPad stereo3d_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
         .filter_frame     = filter_frame,
-        .min_perms        = AV_PERM_READ,
     },
     { NULL }
 };
@@ -461,7 +458,6 @@ static const AVFilterPad stereo3d_outputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_output,
-        .min_perms    = AV_PERM_WRITE,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c
index 7513e2402c236945caa0fdb06ba43b019ecb40d7..e5d2e1c53451213e3e38b2c9c41895124373967d 100644
--- a/libavfilter/vf_subtitles.c
+++ b/libavfilter/vf_subtitles.c
@@ -158,7 +158,7 @@ static int config_input(AVFilterLink *inlink)
 #define AB(c)  (((c)>>8) &0xFF)
 #define AA(c)  ((0xFF-c) &0xFF)
 
-static void overlay_ass_image(AssContext *ass, AVFilterBufferRef *picref,
+static void overlay_ass_image(AssContext *ass, AVFrame *picref,
                               const ASS_Image *image)
 {
     for (; image; image = image->next) {
@@ -167,13 +167,13 @@ static void overlay_ass_image(AssContext *ass, AVFilterBufferRef *picref,
         ff_draw_color(&ass->draw, &color, rgba_color);
         ff_blend_mask(&ass->draw, &color,
                       picref->data, picref->linesize,
-                      picref->video->w, picref->video->h,
+                      picref->width, picref->height,
                       image->bitmap, image->stride, image->w, image->h,
                       3, 0, image->dst_x, image->dst_y);
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -197,7 +197,7 @@ static const AVFilterPad ass_inputs[] = {
         .type             = AVMEDIA_TYPE_VIDEO,
         .filter_frame     = filter_frame,
         .config_props     = config_input,
-        .min_perms        = AV_PERM_READ | AV_PERM_WRITE,
+        .needs_writable   = 1,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_super2xsai.c b/libavfilter/vf_super2xsai.c
index e2db3b43db365a72edb45427c86e0810b1b28a7e..4f25968594a300774dbc485ab891d54462133a50 100644
--- a/libavfilter/vf_super2xsai.c
+++ b/libavfilter/vf_super2xsai.c
@@ -303,23 +303,23 @@ static int config_output(AVFilterLink *outlink)
     return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
 {
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    AVFrame *outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!outpicref) {
-        avfilter_unref_bufferp(&inpicref);
+        av_frame_free(&inpicref);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(outpicref, inpicref);
-    outpicref->video->w = outlink->w;
-    outpicref->video->h = outlink->h;
+    av_frame_copy_props(outpicref, inpicref);
+    outpicref->width  = outlink->w;
+    outpicref->height = outlink->h;
 
     super2xsai(inlink->dst, inpicref->data[0], inpicref->linesize[0],
                outpicref->data[0], outpicref->linesize[0],
                inlink->w, inlink->h);
 
-    avfilter_unref_bufferp(&inpicref);
+    av_frame_free(&inpicref);
     return ff_filter_frame(outlink, outpicref);
 }
 
@@ -329,7 +329,6 @@ static const AVFilterPad super2xsai_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .config_props = config_input,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_swapuv.c b/libavfilter/vf_swapuv.c
index 82cc07c8dc123418471b665e1b265e6920942223..ea9ffcd01ed5beabad763619e25dfc126f1a47c8 100644
--- a/libavfilter/vf_swapuv.c
+++ b/libavfilter/vf_swapuv.c
@@ -29,23 +29,25 @@
 #include "internal.h"
 #include "video.h"
 
-static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
-                                           int w, int h)
+static void do_swap(AVFrame *frame)
 {
-    AVFilterBufferRef *picref =
-        ff_default_get_video_buffer(link, perms, w, h);
-
-    FFSWAP(uint8_t*, picref->data[1], picref->data[2]);
-    FFSWAP(int, picref->linesize[1], picref->linesize[2]);
+    FFSWAP(uint8_t*,     frame->data[1],     frame->data[2]);
+    FFSWAP(int,          frame->linesize[1], frame->linesize[2]);
+    FFSWAP(uint8_t*,     frame->base[1],     frame->base[2]);
+    FFSWAP(uint64_t,     frame->error[1],    frame->error[2]);
+    FFSWAP(AVBufferRef*, frame->buf[1],      frame->buf[2]);
+}
 
+static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
+{
+    AVFrame *picref = ff_default_get_video_buffer(link, w, h);
+    do_swap(picref);
     return picref;
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *inpicref)
+static int filter_frame(AVFilterLink *link, AVFrame *inpicref)
 {
-    FFSWAP(uint8_t*, inpicref->data[1], inpicref->data[2]);
-    FFSWAP(int, inpicref->linesize[1], inpicref->linesize[2]);
-
+    do_swap(inpicref);
     return ff_filter_frame(link->dst->outputs[0], inpicref);
 }
 
diff --git a/libavfilter/vf_thumbnail.c b/libavfilter/vf_thumbnail.c
index 0d245d9dddbbce1008e567b28f53ca67b7c4c873..1a29f186fc5e8f83911e78b3266c6a7e62dc2e9a 100644
--- a/libavfilter/vf_thumbnail.c
+++ b/libavfilter/vf_thumbnail.c
@@ -33,7 +33,7 @@
 #define HIST_SIZE (3*256)
 
 struct thumb_frame {
-    AVFilterBufferRef *buf;     ///< cached frame
+    AVFrame *buf;               ///< cached frame
     int histogram[HIST_SIZE];   ///< RGB color distribution histogram of the frame
 };
 
@@ -86,14 +86,14 @@ static double frame_sum_square_err(const int *hist, const double *median)
     return sum_sq_err;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 {
     int i, j, best_frame_idx = 0;
     double avg_hist[HIST_SIZE] = {0}, sq_err, min_sq_err = -1;
     AVFilterContext *ctx  = inlink->dst;
     ThumbContext *thumb   = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *picref;
+    AVFrame *picref;
     int *hist = thumb->frames[thumb->n].histogram;
     const uint8_t *p = frame->data[0];
 
@@ -135,7 +135,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *frame)
         memset(thumb->frames[i].histogram, 0, sizeof(thumb->frames[i].histogram));
         if (i == best_frame_idx)
             continue;
-        avfilter_unref_bufferp(&thumb->frames[i].buf);
+        av_frame_unref(thumb->frames[i].buf);
     }
     thumb->n = 0;
 
@@ -152,7 +152,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     int i;
     ThumbContext *thumb = ctx->priv;
     for (i = 0; i < thumb->n_frames && thumb->frames[i].buf; i++)
-        avfilter_unref_bufferp(&thumb->frames[i].buf);
+        av_frame_unref(thumb->frames[i].buf);
     av_freep(&thumb->frames);
 }
 
@@ -207,7 +207,6 @@ static const AVFilterPad thumbnail_inputs[] = {
         .name             = "default",
         .type             = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer = ff_null_get_video_buffer,
-        .min_perms        = AV_PERM_PRESERVE,
         .filter_frame     = filter_frame,
     },
     { NULL }
diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c
index e4ced887c8e4e029d080d27ecbae31f07e35a8cc..30c9809374f4f7f386125b9046dc26e4b58aa042 100644
--- a/libavfilter/vf_tile.c
+++ b/libavfilter/vf_tile.c
@@ -40,7 +40,7 @@ typedef struct {
     unsigned nb_frames;
     FFDrawContext draw;
     FFDrawColor blank;
-    AVFilterBufferRef *out_ref;
+    AVFrame *out_ref;
 } TileContext;
 
 #define REASONABLE_SIZE 1024
@@ -138,7 +138,7 @@ static void get_current_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y)
     *y = tile->margin + (inlink->h + tile->padding) * ty;
 }
 
-static void draw_blank_frame(AVFilterContext *ctx, AVFilterBufferRef *out_buf)
+static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf)
 {
     TileContext *tile    = ctx->priv;
     AVFilterLink *inlink = ctx->inputs[0];
@@ -154,7 +154,7 @@ static int end_last_frame(AVFilterContext *ctx)
 {
     TileContext *tile     = ctx->priv;
     AVFilterLink *outlink = ctx->outputs[0];
-    AVFilterBufferRef *out_buf = tile->out_ref;
+    AVFrame *out_buf = tile->out_ref;
     int ret;
 
     while (tile->current < tile->nb_frames)
@@ -168,7 +168,7 @@ static int end_last_frame(AVFilterContext *ctx)
  * buffers are fed to filter_frame in the order they were obtained from
  * get_buffer (think B-frames). */
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
     AVFilterContext *ctx  = inlink->dst;
     TileContext *tile     = ctx->priv;
@@ -176,13 +176,12 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     unsigned x0, y0;
 
     if (!tile->current) {
-        tile->out_ref = ff_get_video_buffer(outlink, AV_PERM_WRITE,
-                                            outlink->w, outlink->h);
+        tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!tile->out_ref)
             return AVERROR(ENOMEM);
-        avfilter_copy_buffer_ref_props(tile->out_ref, picref);
-        tile->out_ref->video->w = outlink->w;
-        tile->out_ref->video->h = outlink->h;
+        av_frame_copy_props(tile->out_ref, picref);
+        tile->out_ref->width  = outlink->w;
+        tile->out_ref->height = outlink->h;
 
         /* fill surface once for margin/padding */
         if (tile->margin || tile->padding)
@@ -198,7 +197,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
                        picref->data, picref->linesize,
                        x0, y0, 0, 0, inlink->w, inlink->h);
 
-    avfilter_unref_bufferp(&picref);
+    av_frame_free(&picref);
     if (++tile->current == tile->nb_frames)
         return end_last_frame(ctx);
 
@@ -230,7 +229,6 @@ static const AVFilterPad tile_inputs[] = {
         .name         = "default",
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 909784e5f71ba2cbfebd04c3c0a3d0217d37fd1e..bce63010b4058f1463a5b69dc8bd0eb45d90db49 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -48,8 +48,8 @@ typedef struct {
     int flags;                  ///< flags affecting interlacing algorithm
     int frame;                  ///< number of the output frame
     int vsub;                   ///< chroma vertical subsampling
-    AVFilterBufferRef *cur;
-    AVFilterBufferRef *next;
+    AVFrame *cur;
+    AVFrame *next;
     uint8_t *black_data[4];     ///< buffer used to fill padded lines
     int black_linesize[4];
 } TInterlaceContext;
@@ -112,8 +112,8 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     TInterlaceContext *tinterlace = ctx->priv;
 
-    avfilter_unref_bufferp(&tinterlace->cur );
-    avfilter_unref_bufferp(&tinterlace->next);
+    av_frame_free(&tinterlace->cur );
+    av_frame_free(&tinterlace->next);
 
     av_opt_free(tinterlace);
     av_freep(&tinterlace->black_data[0]);
@@ -228,15 +228,15 @@ void copy_picture_field(uint8_t *dst[4], int dst_linesize[4],
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
     TInterlaceContext *tinterlace = ctx->priv;
-    AVFilterBufferRef *cur, *next, *out;
+    AVFrame *cur, *next, *out;
     int field, tff, ret;
 
-    avfilter_unref_buffer(tinterlace->cur);
+    av_frame_free(&tinterlace->cur);
     tinterlace->cur  = tinterlace->next;
     tinterlace->next = picref;
 
@@ -249,13 +249,13 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     switch (tinterlace->mode) {
     case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
              * the lower field, generating a double-height video at half framerate */
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out)
             return AVERROR(ENOMEM);
-        avfilter_copy_buffer_ref_props(out, cur);
-        out->video->h = outlink->h;
-        out->video->interlaced = 1;
-        out->video->top_field_first = 1;
+        av_frame_copy_props(out, cur);
+        out->height = outlink->h;
+        out->interlaced_frame = 1;
+        out->top_field_first = 1;
 
         /* write odd frame lines into the upper field of the new frame */
         copy_picture_field(out->data, out->linesize,
@@ -267,20 +267,20 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
                            (const uint8_t **)next->data, next->linesize,
                            inlink->format, inlink->w, inlink->h,
                            FIELD_UPPER_AND_LOWER, 1, FIELD_LOWER, tinterlace->flags);
-        avfilter_unref_bufferp(&tinterlace->next);
+        av_frame_free(&tinterlace->next);
         break;
 
     case MODE_DROP_ODD:  /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
     case MODE_DROP_EVEN: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
-        out = avfilter_ref_buffer(tinterlace->mode == MODE_DROP_EVEN ? cur : next, AV_PERM_READ);
-        avfilter_unref_bufferp(&tinterlace->next);
+        out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next);
+        av_frame_free(&tinterlace->next);
         break;
 
     case MODE_PAD: /* expand each frame to double height, but pad alternate
                     * lines with black; framerate unchanged */
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
-        avfilter_copy_buffer_ref_props(out, cur);
-        out->video->h = outlink->h;
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+        av_frame_copy_props(out, cur);
+        out->height = outlink->h;
 
         field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
         /* copy upper and lower fields */
@@ -300,12 +300,12 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     case MODE_INTERLEAVE_TOP:    /* top    field first */
     case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
         tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out)
             return AVERROR(ENOMEM);
-        avfilter_copy_buffer_ref_props(out, cur);
-        out->video->interlaced = 1;
-        out->video->top_field_first = tff;
+        av_frame_copy_props(out, cur);
+        out->interlaced_frame = 1;
+        out->top_field_first = tff;
 
         /* copy upper/lower field from cur */
         copy_picture_field(out->data, out->linesize,
@@ -319,25 +319,25 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
                            inlink->format, inlink->w, inlink->h,
                            tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
                            tinterlace->flags);
-        avfilter_unref_bufferp(&tinterlace->next);
+        av_frame_free(&tinterlace->next);
         break;
     case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
         /* output current frame first */
-        out = avfilter_ref_buffer(cur, ~AV_PERM_WRITE);
+        out = av_frame_clone(cur);
         if (!out)
             return AVERROR(ENOMEM);
-        out->video->interlaced = 1;
+        out->interlaced_frame = 1;
 
         if ((ret = ff_filter_frame(outlink, out)) < 0)
             return ret;
 
         /* output mix of current and next frame */
-        tff = next->video->top_field_first;
-        out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+        tff = next->top_field_first;
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
         if (!out)
             return AVERROR(ENOMEM);
-        avfilter_copy_buffer_ref_props(out, next);
-        out->video->interlaced = 1;
+        av_frame_copy_props(out, next);
+        out->interlaced_frame = 1;
 
         /* write current frame second field lines into the second field of the new frame */
         copy_picture_field(out->data, out->linesize,
diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c
index 270d346f05a6072b3977c09a4469dc879db8efc2..aafb44efaf61a077a19b47a6c6f553cdf0550a25 100644
--- a/libavfilter/vf_transpose.c
+++ b/libavfilter/vf_transpose.c
@@ -148,47 +148,47 @@ static int config_props_output(AVFilterLink *outlink)
     return 0;
 }
 
-static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
 {
     TransContext *trans = inlink->dst->priv;
 
     return trans->passthrough ?
-        ff_null_get_video_buffer   (inlink, perms, w, h) :
-        ff_default_get_video_buffer(inlink, perms, w, h);
+        ff_null_get_video_buffer   (inlink, w, h) :
+        ff_default_get_video_buffer(inlink, w, h);
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     TransContext *trans = inlink->dst->priv;
     AVFilterLink *outlink = inlink->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int plane;
 
     if (trans->passthrough)
         return ff_filter_frame(outlink, in);
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
 
     out->pts = in->pts;
 
-    if (in->video->sample_aspect_ratio.num == 0) {
-        out->video->sample_aspect_ratio = in->video->sample_aspect_ratio;
+    if (in->sample_aspect_ratio.num == 0) {
+        out->sample_aspect_ratio = in->sample_aspect_ratio;
     } else {
-        out->video->sample_aspect_ratio.num = in->video->sample_aspect_ratio.den;
-        out->video->sample_aspect_ratio.den = in->video->sample_aspect_ratio.num;
+        out->sample_aspect_ratio.num = in->sample_aspect_ratio.den;
+        out->sample_aspect_ratio.den = in->sample_aspect_ratio.num;
     }
 
     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  = in->video->h>>vsub;
-        int outw = out->video->w>>hsub;
-        int outh = out->video->h>>vsub;
+        int inh  = in->height  >> vsub;
+        int outw = out->width  >> hsub;
+        int outh = out->height >> vsub;
         uint8_t *dst, *src;
         int dstlinesize, srclinesize;
         int x, y;
@@ -243,7 +243,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         }
     }
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -253,7 +253,6 @@ static const AVFilterPad avfilter_vf_transpose_inputs[] = {
         .type        = AVMEDIA_TYPE_VIDEO,
         .get_video_buffer= get_video_buffer,
         .filter_frame = filter_frame,
-        .min_perms   = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c
index 8c6e18a1128df68f8ec39fa0ee7626c0edc6801a..0e2891af3eb6653a15f4685759041b8eba05cdf5 100644
--- a/libavfilter/vf_unsharp.c
+++ b/libavfilter/vf_unsharp.c
@@ -258,26 +258,26 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_opt_free(unsharp);
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
+static int filter_frame(AVFilterLink *link, AVFrame *in)
 {
     UnsharpContext *unsharp = link->dst->priv;
     AVFilterLink *outlink   = link->dst->outputs[0];
-    AVFilterBufferRef *out;
+    AVFrame *out;
     int cw = SHIFTUP(link->w, unsharp->hsub);
     int ch = SHIFTUP(link->h, unsharp->vsub);
 
-    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     if (!out) {
-        avfilter_unref_bufferp(&in);
+        av_frame_free(&in);
         return AVERROR(ENOMEM);
     }
-    avfilter_copy_buffer_ref_props(out, in);
+    av_frame_copy_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);
 
-    avfilter_unref_bufferp(&in);
+    av_frame_free(&in);
     return ff_filter_frame(outlink, out);
 }
 
@@ -287,7 +287,6 @@ static const AVFilterPad avfilter_vf_unsharp_inputs[] = {
         .type         = AVMEDIA_TYPE_VIDEO,
         .filter_frame = filter_frame,
         .config_props = config_props,
-        .min_perms    = AV_PERM_READ,
     },
     { NULL }
 };
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index 6077789273285d0c57bc6e3c90a4d46d668c6682..28fa800f3b1ebb32cd855c9bc6070a21b7ef9f77 100644
--- a/libavfilter/vf_vflip.c
+++ b/libavfilter/vf_vflip.c
@@ -43,33 +43,29 @@ static int config_input(AVFilterLink *link)
     return 0;
 }
 
-static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
-                                        int w, int h)
+static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
 {
     FlipContext *flip = link->dst->priv;
-    AVFilterBufferRef *picref;
+    AVFrame *frame;
     int i;
 
-    if (!(perms & AV_PERM_NEG_LINESIZES))
-        return ff_default_get_video_buffer(link, perms, w, h);
-
-    picref = ff_get_video_buffer(link->dst->outputs[0], perms, w, h);
-    if (!picref)
+    frame = ff_get_video_buffer(link->dst->outputs[0], w, h);
+    if (!frame)
         return NULL;
 
     for (i = 0; i < 4; i ++) {
         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
 
-        if (picref->data[i]) {
-            picref->data[i] += (((h + (1<<vsub)-1) >> vsub)-1) * picref->linesize[i];
-            picref->linesize[i] = -picref->linesize[i];
+        if (frame->data[i]) {
+            frame->data[i] += (((h + (1<<vsub) - 1) >> vsub) - 1) * frame->linesize[i];
+            frame->linesize[i] = -frame->linesize[i];
         }
     }
 
-    return picref;
+    return frame;
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     FlipContext *flip = link->dst->priv;
     int i;
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index b7c2d8073ab620e54dcd6d52d8482750317ec998..95f35b2c8ceda2b06310998bf47e78d110d81fd2 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -31,8 +31,6 @@
 #undef NDEBUG
 #include <assert.h>
 
-#define PERM_RWP AV_PERM_WRITE | AV_PERM_PRESERVE | AV_PERM_REUSE
-
 #define CHECK(j)\
     {   int score = FFABS(cur[mrefs + off_left + (j)] - cur[prefs + off_left - (j)])\
                   + FFABS(cur[mrefs  +(j)] - cur[prefs  -(j)])\
@@ -167,15 +165,15 @@ static void filter_edges_16bit(void *dst1, void *prev1, void *cur1, void *next1,
     FILTER(w - 3, w)
 }
 
-static void filter(AVFilterContext *ctx, AVFilterBufferRef *dstpic,
+static void filter(AVFilterContext *ctx, AVFrame *dstpic,
                    int parity, int tff)
 {
     YADIFContext *yadif = ctx->priv;
     int y, i;
 
     for (i = 0; i < yadif->csp->nb_components; i++) {
-        int w = dstpic->video->w;
-        int h = dstpic->video->h;
+        int w = dstpic->width;
+        int h = dstpic->height;
         int refs = yadif->cur->linesize[i];
         int df = (yadif->csp->comp[i].depth_minus1 + 8) / 8;
         int l_edge, l_edge_pix;
@@ -232,19 +230,19 @@ static int return_frame(AVFilterContext *ctx, int is_second)
     int tff, ret;
 
     if (yadif->parity == -1) {
-        tff = yadif->cur->video->interlaced ?
-              yadif->cur->video->top_field_first : 1;
+        tff = yadif->cur->interlaced_frame ?
+              yadif->cur->top_field_first : 1;
     } else {
         tff = yadif->parity ^ 1;
     }
 
     if (is_second) {
-        yadif->out = ff_get_video_buffer(link, PERM_RWP, link->w, link->h);
+        yadif->out = ff_get_video_buffer(link, link->w, link->h);
         if (!yadif->out)
             return AVERROR(ENOMEM);
 
-        avfilter_copy_buffer_ref_props(yadif->out, yadif->cur);
-        yadif->out->video->interlaced = 0;
+        av_frame_copy_props(yadif->out, yadif->cur);
+        yadif->out->interlaced_frame = 0;
     }
 
     filter(ctx, yadif->out, tff ^ !is_second, tff);
@@ -265,47 +263,46 @@ static int return_frame(AVFilterContext *ctx, int is_second)
     return ret;
 }
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
     AVFilterContext *ctx = link->dst;
     YADIFContext *yadif = ctx->priv;
 
-    av_assert0(picref);
+    av_assert0(frame);
 
     if (yadif->frame_pending)
         return_frame(ctx, 1);
 
     if (yadif->prev)
-        avfilter_unref_buffer(yadif->prev);
+        av_frame_free(&yadif->prev);
     yadif->prev = yadif->cur;
     yadif->cur  = yadif->next;
-    yadif->next = picref;
+    yadif->next = frame;
 
     if (!yadif->cur)
         return 0;
 
-    if (yadif->deint && !yadif->cur->video->interlaced) {
-        yadif->out  = avfilter_ref_buffer(yadif->cur, ~AV_PERM_WRITE);
+    if (yadif->deint && !yadif->cur->interlaced_frame) {
+        yadif->out  = av_frame_clone(yadif->cur);
         if (!yadif->out)
             return AVERROR(ENOMEM);
 
-        avfilter_unref_bufferp(&yadif->prev);
+        av_frame_free(&yadif->prev);
         if (yadif->out->pts != AV_NOPTS_VALUE)
             yadif->out->pts *= 2;
         return ff_filter_frame(ctx->outputs[0], yadif->out);
     }
 
     if (!yadif->prev &&
-        !(yadif->prev = avfilter_ref_buffer(yadif->cur, ~AV_PERM_WRITE)))
+        !(yadif->prev = av_frame_clone(yadif->cur)))
         return AVERROR(ENOMEM);
 
-    yadif->out = ff_get_video_buffer(ctx->outputs[0], PERM_RWP,
-                                     link->w, link->h);
+    yadif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h);
     if (!yadif->out)
         return AVERROR(ENOMEM);
 
-    avfilter_copy_buffer_ref_props(yadif->out, yadif->cur);
-    yadif->out->video->interlaced = 0;
+    av_frame_copy_props(yadif->out, yadif->cur);
+    yadif->out->interlaced_frame = 0;
 
     if (yadif->out->pts != AV_NOPTS_VALUE)
         yadif->out->pts *= 2;
@@ -332,7 +329,7 @@ static int request_frame(AVFilterLink *link)
         ret  = ff_request_frame(link->src->inputs[0]);
 
         if (ret == AVERROR_EOF && yadif->cur) {
-            AVFilterBufferRef *next = avfilter_ref_buffer(yadif->next, ~AV_PERM_WRITE);
+            AVFrame *next = av_frame_clone(yadif->next);
 
             if (!next)
                 return AVERROR(ENOMEM);
@@ -379,9 +376,9 @@ static av_cold void uninit(AVFilterContext *ctx)
 {
     YADIFContext *yadif = ctx->priv;
 
-    avfilter_unref_bufferp(&yadif->prev);
-    avfilter_unref_bufferp(&yadif->cur );
-    avfilter_unref_bufferp(&yadif->next);
+    av_frame_free(&yadif->prev);
+    av_frame_free(&yadif->cur );
+    av_frame_free(&yadif->next);
     av_opt_free(yadif);
 }
 
diff --git a/libavfilter/video.c b/libavfilter/video.c
index a493204df2370c2d438a8340f55ac89d0fd3befb..b2740705a8ecfb2789a2dc58f912e06181d36537 100644
--- a/libavfilter/video.c
+++ b/libavfilter/video.c
@@ -24,6 +24,7 @@
 #include <stdio.h>
 
 #include "libavutil/avassert.h"
+#include "libavutil/buffer.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/mem.h"
 
@@ -31,23 +32,21 @@
 #include "internal.h"
 #include "video.h"
 
-AVFilterBufferRef *ff_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
+AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h)
 {
-    return ff_get_video_buffer(link->dst->outputs[0], perms, w, h);
+    return ff_get_video_buffer(link->dst->outputs[0], w, h);
 }
 
-AVFilterBufferRef *ff_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
+/* TODO: set the buffer's priv member to a context structure for the whole
+ * filter chain.  This will allow for a buffer pool instead of the constant
+ * alloc & free cycle currently implemented. */
+AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
 {
-    int linesize[4];
-    uint8_t *data[4];
-    int i;
-    AVFilterBufferRef *picref = NULL;
-    AVFilterPool *pool = link->pool;
-    int full_perms = AV_PERM_READ | AV_PERM_WRITE | AV_PERM_PRESERVE |
-                     AV_PERM_REUSE | AV_PERM_REUSE2 | AV_PERM_ALIGN;
-
-    av_assert1(!(perms & ~(full_perms | AV_PERM_NEG_LINESIZES)));
+    AVFrame *frame = av_frame_alloc();
+    int ret;
 
+#if 0 //POOL
+    AVFilterPool *pool = link->pool;
     if (pool) {
         for (i = 0; i < POOL_SIZE; i++) {
             picref = pool->pic[i];
@@ -71,27 +70,30 @@ AVFilterBufferRef *ff_default_get_video_buffer(AVFilterLink *link, int perms, in
         pool = link->pool = av_mallocz(sizeof(AVFilterPool));
         pool->refcount = 1;
     }
-
-    // align: +2 is needed for swscaler, +16 to be SIMD-friendly
-    if ((i = av_image_alloc(data, linesize, w, h, link->format, 32)) < 0)
+#endif
+    if (!frame)
         return NULL;
 
-    picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize,
-                                                       full_perms, w, h, link->format);
-    if (!picref) {
-        av_free(data[0]);
-        return NULL;
-    }
+    frame->width  = w;
+    frame->height = h;
+    frame->format = link->format;
+
+    ret = av_frame_get_buffer(frame, 32);
+    if (ret < 0)
+        av_frame_free(&frame);
 
+#if 0 //POOL
     memset(data[0], 128, i);
 
     picref->buf->priv = pool;
     picref->buf->free = NULL;
     pool->refcount++;
+#endif
 
-    return picref;
+    return frame;
 }
 
+#if FF_API_AVFILTERBUFFER
 AVFilterBufferRef *
 avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int linesize[4], int perms,
                                           int w, int h, enum AVPixelFormat format)
@@ -136,25 +138,20 @@ fail:
     av_free(pic);
     return NULL;
 }
+#endif
 
-AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
+AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h)
 {
-    AVFilterBufferRef *ret = NULL;
+    AVFrame *ret = NULL;
 
     av_unused char buf[16];
     FF_TPRINTF_START(NULL, get_video_buffer); ff_tlog_link(NULL, link, 0);
-    ff_tlog(NULL, " perms:%s w:%d h:%d\n", ff_get_ref_perms_string(buf, sizeof(buf), perms), w, h);
 
     if (link->dstpad->get_video_buffer)
-        ret = link->dstpad->get_video_buffer(link, perms, w, h);
+        ret = link->dstpad->get_video_buffer(link, w, h);
 
     if (!ret)
-        ret = ff_default_get_video_buffer(link, perms, w, h);
-
-    if (ret)
-        ret->type = AVMEDIA_TYPE_VIDEO;
-
-    FF_TPRINTF_START(NULL, get_video_buffer); ff_tlog_link(NULL, link, 0); ff_tlog(NULL, " returning "); ff_tlog_ref(NULL, ret, 1);
+        ret = ff_default_get_video_buffer(link, w, h);
 
     return ret;
 }
diff --git a/libavfilter/video.h b/libavfilter/video.h
index a6af163aa4456a8afff24fba59b91dc86a59fca6..56c58d6766dd490400468192c6609be88ebd5947 100644
--- a/libavfilter/video.h
+++ b/libavfilter/video.h
@@ -23,22 +23,19 @@
 
 #include "avfilter.h"
 
-AVFilterBufferRef *ff_default_get_video_buffer(AVFilterLink *link,
-                                               int perms, int w, int h);
-AVFilterBufferRef *ff_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h);
+AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h);
+AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h);
 
 /**
  * Request a picture buffer with a specific set of permissions.
  *
  * @param link  the output link to the filter from which the buffer will
  *              be requested
- * @param perms the required access permissions
  * @param w     the minimum width of the buffer to allocate
  * @param h     the minimum height of the buffer to allocate
  * @return      A reference to the buffer. This must be unreferenced with
  *              avfilter_unref_buffer when you are finished with it.
  */
-AVFilterBufferRef *ff_get_video_buffer(AVFilterLink *link, int perms,
-                                       int w, int h);
+AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h);
 
 #endif /* AVFILTER_VIDEO_H */
diff --git a/libavfilter/vsink_nullsink.c b/libavfilter/vsink_nullsink.c
index a37d346eed12b0b31444a6b4c9702709fd17b321..d498aabf801815d5fc815f0c6266bf490f146bf5 100644
--- a/libavfilter/vsink_nullsink.c
+++ b/libavfilter/vsink_nullsink.c
@@ -20,9 +20,9 @@
 #include "internal.h"
 #include "libavutil/internal.h"
 
-static int filter_frame(AVFilterLink *link, AVFilterBufferRef *frame)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
 {
-    avfilter_unref_bufferp(&frame);
+    av_frame_free(&frame);
     return 0;
 }
 
diff --git a/libavfilter/vsrc_cellauto.c b/libavfilter/vsrc_cellauto.c
index 1431717a5f01c981796eb22349cbea5057c58a90..cadd9fd6ab85d643d48381baf4a87fff79d8459b 100644
--- a/libavfilter/vsrc_cellauto.c
+++ b/libavfilter/vsrc_cellauto.c
@@ -272,7 +272,7 @@ static void evolve(AVFilterContext *ctx)
     cellauto->generation++;
 }
 
-static void fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void fill_picture(AVFilterContext *ctx, AVFrame *picref)
 {
     CellAutoContext *cellauto = ctx->priv;
     int i, j, k, row_idx = 0;
@@ -303,9 +303,8 @@ static void fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
 static int request_frame(AVFilterLink *outlink)
 {
     CellAutoContext *cellauto = outlink->src->priv;
-    AVFilterBufferRef *picref =
-        ff_get_video_buffer(outlink, AV_PERM_WRITE, cellauto->w, cellauto->h);
-    picref->video->sample_aspect_ratio = (AVRational) {1, 1};
+    AVFrame *picref = ff_get_video_buffer(outlink, cellauto->w, cellauto->h);
+    picref->sample_aspect_ratio = (AVRational) {1, 1};
     if (cellauto->generation == 0 && cellauto->start_full) {
         int i;
         for (i = 0; i < cellauto->h-1; i++)
@@ -315,7 +314,6 @@ static int request_frame(AVFilterLink *outlink)
     evolve(outlink->src);
 
     picref->pts = cellauto->pts++;
-    picref->pos = -1;
 
 #ifdef DEBUG
     show_cellauto_row(outlink->src);
diff --git a/libavfilter/vsrc_life.c b/libavfilter/vsrc_life.c
index d548ab46e08a811c8f29ad5f48fbd3dc11499aa6..8df446d287e9f245cf5d0e265930e7283651baab 100644
--- a/libavfilter/vsrc_life.c
+++ b/libavfilter/vsrc_life.c
@@ -73,7 +73,7 @@ typedef struct {
     uint8_t death_color[4];
     uint8_t  mold_color[4];
     AVLFG lfg;
-    void (*draw)(AVFilterContext*, AVFilterBufferRef*);
+    void (*draw)(AVFilterContext*, AVFrame*);
 } LifeContext;
 
 #define ALIVE_CELL 0xFF
@@ -375,7 +375,7 @@ static void evolve(AVFilterContext *ctx)
     life->buf_idx = !life->buf_idx;
 }
 
-static void fill_picture_monoblack(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void fill_picture_monoblack(AVFilterContext *ctx, AVFrame *picref)
 {
     LifeContext *life = ctx->priv;
     uint8_t *buf = life->buf[life->buf_idx];
@@ -400,7 +400,7 @@ static void fill_picture_monoblack(AVFilterContext *ctx, AVFilterBufferRef *picr
 // apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
 #define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
 
-static void fill_picture_rgb(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void fill_picture_rgb(AVFilterContext *ctx, AVFrame *picref)
 {
     LifeContext *life = ctx->priv;
     uint8_t *buf = life->buf[life->buf_idx];
@@ -430,10 +430,9 @@ static void fill_picture_rgb(AVFilterContext *ctx, AVFilterBufferRef *picref)
 static int request_frame(AVFilterLink *outlink)
 {
     LifeContext *life = outlink->src->priv;
-    AVFilterBufferRef *picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, life->w, life->h);
-    picref->video->sample_aspect_ratio = (AVRational) {1, 1};
+    AVFrame *picref = ff_get_video_buffer(outlink, life->w, life->h);
+    picref->sample_aspect_ratio = (AVRational) {1, 1};
     picref->pts = life->pts++;
-    picref->pos = -1;
 
     life->draw(outlink->src, picref);
     evolve(outlink->src);
diff --git a/libavfilter/vsrc_mandelbrot.c b/libavfilter/vsrc_mandelbrot.c
index 1244edfee727c28e77691ff4f19d9eb631820ac9..c6f3550b47935210140b6193fc79304b6d37df61 100644
--- a/libavfilter/vsrc_mandelbrot.c
+++ b/libavfilter/vsrc_mandelbrot.c
@@ -382,10 +382,9 @@ static void draw_mandelbrot(AVFilterContext *ctx, uint32_t *color, int linesize,
 static int request_frame(AVFilterLink *link)
 {
     MBContext *mb = link->src->priv;
-    AVFilterBufferRef *picref = ff_get_video_buffer(link, AV_PERM_WRITE, mb->w, mb->h);
-    picref->video->sample_aspect_ratio = (AVRational) {1, 1};
+    AVFrame *picref = ff_get_video_buffer(link, mb->w, mb->h);
+    picref->sample_aspect_ratio = (AVRational) {1, 1};
     picref->pts = mb->pts++;
-    picref->pos = -1;
 
     draw_mandelbrot(link->src, (uint32_t*)picref->data[0], picref->linesize[0]/4, picref->pts);
     ff_filter_frame(link, picref);
diff --git a/libavfilter/vsrc_mptestsrc.c b/libavfilter/vsrc_mptestsrc.c
index d526ee2cc900dbcc8c29f09bdaf0b8ecd13955cc..a6d938c00ab1034034b2a74a5646be23198de69a 100644
--- a/libavfilter/vsrc_mptestsrc.c
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -323,14 +323,14 @@ static int query_formats(AVFilterContext *ctx)
 static int request_frame(AVFilterLink *outlink)
 {
     MPTestContext *test = outlink->src->priv;
-    AVFilterBufferRef *picref;
+    AVFrame *picref;
     int w = WIDTH, h = HEIGHT, ch = h>>test->vsub;
     unsigned int frame = test->frame_nb;
     enum test_type tt = test->test;
 
     if (test->max_pts >= 0 && test->pts > test->max_pts)
         return AVERROR_EOF;
-    picref = ff_get_video_buffer(outlink, AV_PERM_WRITE, w, h);
+    picref = ff_get_video_buffer(outlink, w, h);
     picref->pts = test->pts++;
 
     // clean image
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index f5e37f8b7275e33d929c73f7ea620beeb6ed251a..22f163c1e19938c49fb4afdcc3c4f9437dda5b30 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -58,9 +58,9 @@ typedef struct {
     AVRational sar;             ///< sample aspect ratio
     int nb_decimals;
     int draw_once;              ///< draw only the first frame, always put out the same picture
-    AVFilterBufferRef *picref;  ///< cached reference containing the painted picture
+    AVFrame *picref;            ///< cached reference containing the painted picture
 
-    void (* fill_picture_fn)(AVFilterContext *ctx, AVFilterBufferRef *picref);
+    void (* fill_picture_fn)(AVFilterContext *ctx, AVFrame *frame);
 
     /* only used by color */
     char *color_str;
@@ -150,7 +150,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     TestSourceContext *test = ctx->priv;
 
     av_opt_free(test);
-    avfilter_unref_bufferp(&test->picref);
+    av_frame_free(&test->picref);
 }
 
 static int config_props(AVFilterLink *outlink)
@@ -169,7 +169,7 @@ static int config_props(AVFilterLink *outlink)
 static int request_frame(AVFilterLink *outlink)
 {
     TestSourceContext *test = outlink->src->priv;
-    AVFilterBufferRef *outpicref;
+    AVFrame *frame;
 
     if (test->duration >= 0 &&
         av_rescale_q(test->pts, test->time_base, AV_TIME_BASE_Q) >= test->duration)
@@ -178,31 +178,29 @@ static int request_frame(AVFilterLink *outlink)
     if (test->draw_once) {
         if (!test->picref) {
             test->picref =
-                ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_PRESERVE|AV_PERM_REUSE,
-                                    test->w, test->h);
+                ff_get_video_buffer(outlink, test->w, test->h);
             if (!test->picref)
                 return AVERROR(ENOMEM);
             test->fill_picture_fn(outlink->src, test->picref);
         }
-        outpicref = avfilter_ref_buffer(test->picref, ~AV_PERM_WRITE);
+        frame = av_frame_clone(test->picref);
     } else
-        outpicref = ff_get_video_buffer(outlink, AV_PERM_WRITE, test->w, test->h);
+        frame = ff_get_video_buffer(outlink, test->w, test->h);
 
-    if (!outpicref)
+    if (!frame)
         return AVERROR(ENOMEM);
-    outpicref->pts = test->pts;
-    outpicref->pos = -1;
-    outpicref->video->key_frame = 1;
-    outpicref->video->interlaced = 0;
-    outpicref->video->pict_type = AV_PICTURE_TYPE_I;
-    outpicref->video->sample_aspect_ratio = test->sar;
+    frame->pts                 = test->pts;
+    frame->key_frame           = 1;
+    frame->interlaced_frame    = 0;
+    frame->pict_type           = AV_PICTURE_TYPE_I;
+    frame->sample_aspect_ratio = test->sar;
     if (!test->draw_once)
-        test->fill_picture_fn(outlink->src, outpicref);
+        test->fill_picture_fn(outlink->src, frame);
 
     test->pts++;
     test->nb_frame++;
 
-    return ff_filter_frame(outlink, outpicref);
+    return ff_filter_frame(outlink, frame);
 }
 
 #if CONFIG_COLOR_FILTER
@@ -210,7 +208,7 @@ static int request_frame(AVFilterLink *outlink)
 #define color_options options
 AVFILTER_DEFINE_CLASS(color);
 
-static void color_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void color_fill_picture(AVFilterContext *ctx, AVFrame *picref)
 {
     TestSourceContext *test = ctx->priv;
     ff_fill_rectangle(&test->draw, &test->color,
@@ -287,7 +285,7 @@ AVFilter avfilter_vsrc_color = {
 #define nullsrc_options options
 AVFILTER_DEFINE_CLASS(nullsrc);
 
-static void nullsrc_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref) { }
+static void nullsrc_fill_picture(AVFilterContext *ctx, AVFrame *picref) { }
 
 static av_cold int nullsrc_init(AVFilterContext *ctx, const char *args)
 {
@@ -398,7 +396,7 @@ static void draw_digit(int digit, uint8_t *dst, unsigned dst_linesize,
 
 #define GRADIENT_SIZE (6 * 256)
 
-static void test_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void test_fill_picture(AVFilterContext *ctx, AVFrame *frame)
 {
     TestSourceContext *test = ctx->priv;
     uint8_t *p, *p0;
@@ -412,9 +410,9 @@ static void test_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
     int seg_size;
     int second;
     int i;
-    uint8_t *data = picref->data[0];
-    int width  = picref->video->w;
-    int height = picref->video->h;
+    uint8_t *data = frame->data[0];
+    int width  = frame->width;
+    int height = frame->height;
 
     /* draw colored bars and circle */
     radius = (width + height) / 4;
@@ -444,11 +442,11 @@ static void test_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
         }
         quad0 += dquad_y;
         dquad_y += 2;
-        p0 += picref->linesize[0];
+        p0 += frame->linesize[0];
     }
 
     /* draw sliding color line */
-    p0 = p = data + picref->linesize[0] * height * 3/4;
+    p0 = p = data + frame->linesize[0] * height * 3/4;
     grad = (256 * test->nb_frame * test->time_base.num / test->time_base.den) %
         GRADIENT_SIZE;
     rgrad = 0;
@@ -478,8 +476,8 @@ static void test_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
     }
     p = p0;
     for (y = height / 8; y > 0; y--) {
-        memcpy(p+picref->linesize[0], p, 3 * width);
-        p += picref->linesize[0];
+        memcpy(p+frame->linesize[0], p, 3 * width);
+        p += frame->linesize[0];
     }
 
     /* draw digits */
@@ -492,10 +490,10 @@ static void test_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
         second = (int)time;
         x = width - (width - seg_size * 64) / 2;
         y = (height - seg_size * 13) / 2;
-        p = data + (x*3 + y * picref->linesize[0]);
+        p = data + (x*3 + y * frame->linesize[0]);
         for (i = 0; i < 8; i++) {
             p -= 3 * 8 * seg_size;
-            draw_digit(second % 10, p, picref->linesize[0], seg_size);
+            draw_digit(second % 10, p, frame->linesize[0], seg_size);
             second /= 10;
             if (second == 0)
                 break;
@@ -588,13 +586,13 @@ static void rgbtest_put_pixel(uint8_t *dst, int dst_linesize,
     }
 }
 
-static void rgbtest_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void rgbtest_fill_picture(AVFilterContext *ctx, AVFrame *frame)
 {
     TestSourceContext *test = ctx->priv;
-    int x, y, w = picref->video->w, h = picref->video->h;
+    int x, y, w = frame->width, h = frame->height;
 
     for (y = 0; y < h; y++) {
-         for (x = 0; x < picref->video->w; x++) {
+         for (x = 0; x < w; x++) {
              int c = 256*x/w;
              int r = 0, g = 0, b = 0;
 
@@ -602,7 +600,7 @@ static void rgbtest_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref
              else if (3*y < 2*h) g = c;
              else                b = c;
 
-             rgbtest_put_pixel(picref->data[0], picref->linesize[0], x, y, r, g, b,
+             rgbtest_put_pixel(frame->data[0], frame->linesize[0], x, y, r, g, b,
                                ctx->outputs[0]->format, test->rgba_map);
          }
      }
@@ -703,7 +701,7 @@ static const uint8_t pos4ire[4] = {  29,  29,  29, 255 }; /* 11.5% intensity bla
 static const uint8_t i_pixel[4] = {   0,  68, 130, 255 };
 static const uint8_t q_pixel[4] = {  67,   0, 130, 255 };
 
-static void smptebars_fill_picture(AVFilterContext *ctx, AVFilterBufferRef *picref)
+static void smptebars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
 {
     TestSourceContext *test = ctx->priv;
     FFDrawColor color;
diff --git a/libavfilter/yadif.h b/libavfilter/yadif.h
index 50fc856bf2ca1547747a5c4d3ac856c4516836c6..cfa9752b5abbdaf9d347484ea87bc5242deded1e 100644
--- a/libavfilter/yadif.h
+++ b/libavfilter/yadif.h
@@ -49,10 +49,10 @@ typedef struct YADIFContext {
 
     int frame_pending;
 
-    AVFilterBufferRef *cur;
-    AVFilterBufferRef *next;
-    AVFilterBufferRef *prev;
-    AVFilterBufferRef *out;
+    AVFrame *cur;
+    AVFrame *next;
+    AVFrame *prev;
+    AVFrame *out;
 
     /**
      * Required alignment for filter_line
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 11c0aa163c5743ea8d3a056a9e513068fc340f49..95d018932bf49f6903dbbfbc390aa4592dfc970b 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -397,6 +397,7 @@ int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
     dst->opaque              = src->opaque;
     dst->pkt_pts             = src->pkt_pts;
     dst->pkt_dts             = src->pkt_dts;
+    dst->pkt_pos             = src->pkt_pos;
     dst->quality             = src->quality;
     dst->coded_picture_number = src->coded_picture_number;
     dst->display_picture_number = src->display_picture_number;