diff mbox series

[FFmpeg-devel,v2,1/1] avfilter/buffersink: Add video frame allocation callback

Message ID 20230722164157.964161-2-jc@kynesim.co.uk
State New
Headers show
Series avfilter/buffersink: Add user video frame allocation | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

John Cox July 22, 2023, 4:41 p.m. UTC
Add a callback to enable user allocation of video frames on the final
stage of a filter chain.

Signed-off-by: John Cox <jc@kynesim.co.uk>
---
 libavfilter/buffersink.c | 21 +++++++++++++++++++++
 libavfilter/buffersink.h | 27 +++++++++++++++++++++++++++
 libavfilter/version.h    |  2 +-
 3 files changed, 49 insertions(+), 1 deletion(-)

Comments

John Cox July 22, 2023, 4:45 p.m. UTC | #1
Finger trouble - repost of previous patch - please ignore

Sorry

JC

>Add a callback to enable user allocation of video frames on the final
>stage of a filter chain.
>
>Signed-off-by: John Cox <jc@kynesim.co.uk>
>---
> libavfilter/buffersink.c | 21 +++++++++++++++++++++
> libavfilter/buffersink.h | 27 +++++++++++++++++++++++++++
> libavfilter/version.h    |  2 +-
> 3 files changed, 49 insertions(+), 1 deletion(-)
>
>diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
>index 306c283f77..070b743186 100644
>--- a/libavfilter/buffersink.c
>+++ b/libavfilter/buffersink.c
>@@ -62,6 +62,11 @@ typedef struct BufferSinkContext {
>     int sample_rates_size;
> 
>     AVFrame *peeked_frame;
>+
>+    union {
>+        av_buffersink_alloc_video_frame * video;
>+    } alloc_cb;
>+    void * alloc_v;
> } BufferSinkContext;
> 
> #define NB_ITEMS(list) (list ## _size / sizeof(*list))
>@@ -154,6 +159,21 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
>     return get_frame_internal(ctx, frame, 0, nb_samples);
> }
> 
>+static AVFrame * alloc_video_buffer(AVFilterLink *link, int w, int h)
>+{
>+    AVFilterContext * const ctx = link->dst;
>+    BufferSinkContext * const bs = ctx->priv;
>+    return bs->alloc_cb.video ? bs->alloc_cb.video(ctx, bs->alloc_v, w, h) :
>+        ff_default_get_video_buffer(link, w, h);
>+}
>+
>+void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v)
>+{
>+    BufferSinkContext * const bs = ctx->priv;
>+    bs->alloc_cb.video = cb;
>+    bs->alloc_v = v;
>+}
>+
> static av_cold int common_init(AVFilterContext *ctx)
> {
>     BufferSinkContext *buf = ctx->priv;
>@@ -381,6 +401,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
>     {
>         .name = "default",
>         .type = AVMEDIA_TYPE_VIDEO,
>+        .get_buffer = {.video = alloc_video_buffer},
>     },
> };
> 
>diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
>index 64e08de53e..73f0ddc476 100644
>--- a/libavfilter/buffersink.h
>+++ b/libavfilter/buffersink.h
>@@ -166,6 +166,33 @@ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
>  */
> int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
> 
>+/**
>+ * Callback from av_buffersink_set_alloc_video_frame to allocate 
>+ * a frame 
>+ *  
>+ * @param ctx pointer to a context of the abuffersink AVFilter.
>+ * @param v opaque pointer passed to 
>+ *          av_buffersink_set_alloc_video_frame
>+ * @param w width of frame to allocate 
>+ * @param height of frame to allocate 
>+ *  
>+ * @return 
>+ *         - The newly allocated frame
>+ *         - NULL if error
>+ */
>+typedef AVFrame * av_buffersink_alloc_video_frame(AVFilterContext * ctx, void * v, int w, int h);
>+
>+/**
>+ * Set a video frame allocation method for buffersink
>+ *
>+ * @param ctx pointer to a context of the abuffersink AVFilter.
>+ * @param cb Callback to the allocation function. If set to NULL 
>+ *           then the default avfilter allocation function will
>+ *           be used.
>+ * @param v  Opaque to pass to the allocation function
>+ */
>+void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v);
>+
> /**
>  * @}
>  */
>diff --git a/libavfilter/version.h b/libavfilter/version.h
>index c001693e3c..54950497be 100644
>--- a/libavfilter/version.h
>+++ b/libavfilter/version.h
>@@ -31,7 +31,7 @@
> 
> #include "version_major.h"
> 
>-#define LIBAVFILTER_VERSION_MINOR   8
>+#define LIBAVFILTER_VERSION_MINOR   9
> #define LIBAVFILTER_VERSION_MICRO 102
> 
>
Nicolas George July 22, 2023, 4:46 p.m. UTC | #2
John Cox (12023-07-22):
> Finger trouble - repost of previous patch - please ignore

No problem, I was about to make the remark. But please do not Cc people
who have not asked for it. Especially when the mail says "Reply-To:
ffmpeg-devel@ffmpeg.org".

Regards,
Marvin Scholz July 22, 2023, 6:54 p.m. UTC | #3
On 22 Jul 2023, at 18:41, John Cox wrote:

> Add a callback to enable user allocation of video frames on the final
> stage of a filter chain.
>
> Signed-off-by: John Cox <jc@kynesim.co.uk>
> ---
>  libavfilter/buffersink.c | 21 +++++++++++++++++++++
>  libavfilter/buffersink.h | 27 +++++++++++++++++++++++++++
>  libavfilter/version.h    |  2 +-
>  3 files changed, 49 insertions(+), 1 deletion(-)
>
> diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
> index 306c283f77..070b743186 100644
> --- a/libavfilter/buffersink.c
> +++ b/libavfilter/buffersink.c
> @@ -62,6 +62,11 @@ typedef struct BufferSinkContext {
>      int sample_rates_size;
>
>      AVFrame *peeked_frame;
> +
> +    union {
> +        av_buffersink_alloc_video_frame * video;
> +    } alloc_cb;
> +    void * alloc_v;
>  } BufferSinkContext;
>
>  #define NB_ITEMS(list) (list ## _size / sizeof(*list))
> @@ -154,6 +159,21 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
>      return get_frame_internal(ctx, frame, 0, nb_samples);
>  }
>
> +static AVFrame * alloc_video_buffer(AVFilterLink *link, int w, int h)
> +{
> +    AVFilterContext * const ctx = link->dst;
> +    BufferSinkContext * const bs = ctx->priv;
> +    return bs->alloc_cb.video ? bs->alloc_cb.video(ctx, bs->alloc_v, w, h) :
> +        ff_default_get_video_buffer(link, w, h);
> +}
> +
> +void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v)
> +{
> +    BufferSinkContext * const bs = ctx->priv;
> +    bs->alloc_cb.video = cb;
> +    bs->alloc_v = v;
> +}
> +
>  static av_cold int common_init(AVFilterContext *ctx)
>  {
>      BufferSinkContext *buf = ctx->priv;
> @@ -381,6 +401,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
>      {
>          .name = "default",
>          .type = AVMEDIA_TYPE_VIDEO,
> +        .get_buffer = {.video = alloc_video_buffer},
>      },
>  };
>
> diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
> index 64e08de53e..73f0ddc476 100644
> --- a/libavfilter/buffersink.h
> +++ b/libavfilter/buffersink.h
> @@ -166,6 +166,33 @@ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
>   */
>  int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
>
> +/**
> + * Callback from av_buffersink_set_alloc_video_frame to allocate
> + * a frame
> + *
> + * @param ctx pointer to a context of the abuffersink AVFilter.
> + * @param v opaque pointer passed to
> + *          av_buffersink_set_alloc_video_frame

Nit:

You can use @ref av_buffersink_set_alloc_video_frame  or even
shorter ::av_buffersink_set_alloc_video_frame to get a proper
reference to that function that will be linked.

> + * @param w width of frame to allocate
> + * @param height of frame to allocate
> + *
> + * @return
> + *         - The newly allocated frame
> + *         - NULL if error

Nit:

This can use retval, for example like that:

@retval AVFrame* The newly allocated frame
@retval NULL     Error allocating the frame

> + */
> +typedef AVFrame * av_buffersink_alloc_video_frame(AVFilterContext * ctx, void * v, int w, int h);
> +
> +/**
> + * Set a video frame allocation method for buffersink
> + *
> + * @param ctx pointer to a context of the abuffersink AVFilter.
> + * @param cb Callback to the allocation function. If set to NULL
> + *           then the default avfilter allocation function will
> + *           be used.
> + * @param v  Opaque to pass to the allocation function
> + */
> +void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v);
> +
>  /**
>   * @}
>   */
> diff --git a/libavfilter/version.h b/libavfilter/version.h
> index c001693e3c..54950497be 100644
> --- a/libavfilter/version.h
> +++ b/libavfilter/version.h
> @@ -31,7 +31,7 @@
>
>  #include "version_major.h"
>
> -#define LIBAVFILTER_VERSION_MINOR   8
> +#define LIBAVFILTER_VERSION_MINOR   9
>  #define LIBAVFILTER_VERSION_MICRO 102
>
>
> -- 
> 2.39.2
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
John Cox July 22, 2023, 7:10 p.m. UTC | #4
On Sat, 22 Jul 2023 20:54:04 +0200, you wrote:

>On 22 Jul 2023, at 18:41, John Cox wrote:
>
>> Add a callback to enable user allocation of video frames on the final
>> stage of a filter chain.
>>
>> Signed-off-by: John Cox <jc@kynesim.co.uk>
>> ---
>>  libavfilter/buffersink.c | 21 +++++++++++++++++++++
>>  libavfilter/buffersink.h | 27 +++++++++++++++++++++++++++
>>  libavfilter/version.h    |  2 +-
>>  3 files changed, 49 insertions(+), 1 deletion(-)
>>
>> diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
>> index 306c283f77..070b743186 100644
>> --- a/libavfilter/buffersink.c
>> +++ b/libavfilter/buffersink.c
>> @@ -62,6 +62,11 @@ typedef struct BufferSinkContext {
>>      int sample_rates_size;
>>
>>      AVFrame *peeked_frame;
>> +
>> +    union {
>> +        av_buffersink_alloc_video_frame * video;
>> +    } alloc_cb;
>> +    void * alloc_v;
>>  } BufferSinkContext;
>>
>>  #define NB_ITEMS(list) (list ## _size / sizeof(*list))
>> @@ -154,6 +159,21 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
>>      return get_frame_internal(ctx, frame, 0, nb_samples);
>>  }
>>
>> +static AVFrame * alloc_video_buffer(AVFilterLink *link, int w, int h)
>> +{
>> +    AVFilterContext * const ctx = link->dst;
>> +    BufferSinkContext * const bs = ctx->priv;
>> +    return bs->alloc_cb.video ? bs->alloc_cb.video(ctx, bs->alloc_v, w, h) :
>> +        ff_default_get_video_buffer(link, w, h);
>> +}
>> +
>> +void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v)
>> +{
>> +    BufferSinkContext * const bs = ctx->priv;
>> +    bs->alloc_cb.video = cb;
>> +    bs->alloc_v = v;
>> +}
>> +
>>  static av_cold int common_init(AVFilterContext *ctx)
>>  {
>>      BufferSinkContext *buf = ctx->priv;
>> @@ -381,6 +401,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
>>      {
>>          .name = "default",
>>          .type = AVMEDIA_TYPE_VIDEO,
>> +        .get_buffer = {.video = alloc_video_buffer},
>>      },
>>  };
>>
>> diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
>> index 64e08de53e..73f0ddc476 100644
>> --- a/libavfilter/buffersink.h
>> +++ b/libavfilter/buffersink.h
>> @@ -166,6 +166,33 @@ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
>>   */
>>  int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
>>
>> +/**
>> + * Callback from av_buffersink_set_alloc_video_frame to allocate
>> + * a frame
>> + *
>> + * @param ctx pointer to a context of the abuffersink AVFilter.
>> + * @param v opaque pointer passed to
>> + *          av_buffersink_set_alloc_video_frame
>
>Nit:
>
>You can use @ref av_buffersink_set_alloc_video_frame  or even
>shorter ::av_buffersink_set_alloc_video_frame to get a proper
>reference to that function that will be linked.

Thanks - will do - Is documentation built from this? I had a quick look
to see if I could find some output to verify what I'd done but I failed
to find it.

>> + * @param w width of frame to allocate
>> + * @param height of frame to allocate
>> + *
>> + * @return
>> + *         - The newly allocated frame
>> + *         - NULL if error
>
>Nit:
>
>This can use retval, for example like that:
>
>@retval AVFrame* The newly allocated frame
>@retval NULL     Error allocating the frame

Will do.

Ta

JC

>> + */
>> +typedef AVFrame * av_buffersink_alloc_video_frame(AVFilterContext * ctx, void * v, int w, int h);
>> +
>> +/**
>> + * Set a video frame allocation method for buffersink
>> + *
>> + * @param ctx pointer to a context of the abuffersink AVFilter.
>> + * @param cb Callback to the allocation function. If set to NULL
>> + *           then the default avfilter allocation function will
>> + *           be used.
>> + * @param v  Opaque to pass to the allocation function
>> + */
>> +void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v);
>> +
>>  /**
>>   * @}
>>   */
>> diff --git a/libavfilter/version.h b/libavfilter/version.h
>> index c001693e3c..54950497be 100644
>> --- a/libavfilter/version.h
>> +++ b/libavfilter/version.h
>> @@ -31,7 +31,7 @@
>>
>>  #include "version_major.h"
>>
>> -#define LIBAVFILTER_VERSION_MINOR   8
>> +#define LIBAVFILTER_VERSION_MINOR   9
>>  #define LIBAVFILTER_VERSION_MICRO 102
>>
>>
>> -- 
>> 2.39.2
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>_______________________________________________
>ffmpeg-devel mailing list
>ffmpeg-devel@ffmpeg.org
>https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>To unsubscribe, visit link above, or email
>ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Marvin Scholz July 22, 2023, 7:27 p.m. UTC | #5
On 22 Jul 2023, at 21:10, John Cox wrote:

> On Sat, 22 Jul 2023 20:54:04 +0200, you wrote:
>
>> On 22 Jul 2023, at 18:41, John Cox wrote:
>>
>>> Add a callback to enable user allocation of video frames on the final
>>> stage of a filter chain.
>>>
>>> Signed-off-by: John Cox <jc@kynesim.co.uk>
>>> ---
>>>  libavfilter/buffersink.c | 21 +++++++++++++++++++++
>>>  libavfilter/buffersink.h | 27 +++++++++++++++++++++++++++
>>>  libavfilter/version.h    |  2 +-
>>>  3 files changed, 49 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
>>> index 306c283f77..070b743186 100644
>>> --- a/libavfilter/buffersink.c
>>> +++ b/libavfilter/buffersink.c
>>> @@ -62,6 +62,11 @@ typedef struct BufferSinkContext {
>>>      int sample_rates_size;
>>>
>>>      AVFrame *peeked_frame;
>>> +
>>> +    union {
>>> +        av_buffersink_alloc_video_frame * video;
>>> +    } alloc_cb;
>>> +    void * alloc_v;
>>>  } BufferSinkContext;
>>>
>>>  #define NB_ITEMS(list) (list ## _size / sizeof(*list))
>>> @@ -154,6 +159,21 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
>>>      return get_frame_internal(ctx, frame, 0, nb_samples);
>>>  }
>>>
>>> +static AVFrame * alloc_video_buffer(AVFilterLink *link, int w, int h)
>>> +{
>>> +    AVFilterContext * const ctx = link->dst;
>>> +    BufferSinkContext * const bs = ctx->priv;
>>> +    return bs->alloc_cb.video ? bs->alloc_cb.video(ctx, bs->alloc_v, w, h) :
>>> +        ff_default_get_video_buffer(link, w, h);
>>> +}
>>> +
>>> +void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v)
>>> +{
>>> +    BufferSinkContext * const bs = ctx->priv;
>>> +    bs->alloc_cb.video = cb;
>>> +    bs->alloc_v = v;
>>> +}
>>> +
>>>  static av_cold int common_init(AVFilterContext *ctx)
>>>  {
>>>      BufferSinkContext *buf = ctx->priv;
>>> @@ -381,6 +401,7 @@ static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
>>>      {
>>>          .name = "default",
>>>          .type = AVMEDIA_TYPE_VIDEO,
>>> +        .get_buffer = {.video = alloc_video_buffer},
>>>      },
>>>  };
>>>
>>> diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
>>> index 64e08de53e..73f0ddc476 100644
>>> --- a/libavfilter/buffersink.h
>>> +++ b/libavfilter/buffersink.h
>>> @@ -166,6 +166,33 @@ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
>>>   */
>>>  int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
>>>
>>> +/**
>>> + * Callback from av_buffersink_set_alloc_video_frame to allocate
>>> + * a frame
>>> + *
>>> + * @param ctx pointer to a context of the abuffersink AVFilter.
>>> + * @param v opaque pointer passed to
>>> + *          av_buffersink_set_alloc_video_frame
>>
>> Nit:
>>
>> You can use @ref av_buffersink_set_alloc_video_frame  or even
>> shorter ::av_buffersink_set_alloc_video_frame to get a proper
>> reference to that function that will be linked.
>
> Thanks - will do - Is documentation built from this? I had a quick look
> to see if I could find some output to verify what I'd done but I failed
> to find it.

You can generate it (if you have doxygen installed) by running:

make apidoc

and it will end up in doc/doxy/html.

>
>>> + * @param w width of frame to allocate
>>> + * @param height of frame to allocate
>>> + *
>>> + * @return
>>> + *         - The newly allocated frame
>>> + *         - NULL if error
>>
>> Nit:
>>
>> This can use retval, for example like that:
>>
>> @retval AVFrame* The newly allocated frame
>> @retval NULL     Error allocating the frame
>
> Will do.
>
> Ta
>
> JC
>
>>> + */
>>> +typedef AVFrame * av_buffersink_alloc_video_frame(AVFilterContext * ctx, void * v, int w, int h);
>>> +
>>> +/**
>>> + * Set a video frame allocation method for buffersink
>>> + *
>>> + * @param ctx pointer to a context of the abuffersink AVFilter.
>>> + * @param cb Callback to the allocation function. If set to NULL
>>> + *           then the default avfilter allocation function will
>>> + *           be used.
>>> + * @param v  Opaque to pass to the allocation function
>>> + */
>>> +void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v);
>>> +
>>>  /**
>>>   * @}
>>>   */
>>> diff --git a/libavfilter/version.h b/libavfilter/version.h
>>> index c001693e3c..54950497be 100644
>>> --- a/libavfilter/version.h
>>> +++ b/libavfilter/version.h
>>> @@ -31,7 +31,7 @@
>>>
>>>  #include "version_major.h"
>>>
>>> -#define LIBAVFILTER_VERSION_MINOR   8
>>> +#define LIBAVFILTER_VERSION_MINOR   9
>>>  #define LIBAVFILTER_VERSION_MICRO 102
>>>
>>>
>>> -- 
>>> 2.39.2
>>>
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>
>>> To unsubscribe, visit link above, or email
>>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 306c283f77..070b743186 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -62,6 +62,11 @@  typedef struct BufferSinkContext {
     int sample_rates_size;
 
     AVFrame *peeked_frame;
+
+    union {
+        av_buffersink_alloc_video_frame * video;
+    } alloc_cb;
+    void * alloc_v;
 } BufferSinkContext;
 
 #define NB_ITEMS(list) (list ## _size / sizeof(*list))
@@ -154,6 +159,21 @@  int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
     return get_frame_internal(ctx, frame, 0, nb_samples);
 }
 
+static AVFrame * alloc_video_buffer(AVFilterLink *link, int w, int h)
+{
+    AVFilterContext * const ctx = link->dst;
+    BufferSinkContext * const bs = ctx->priv;
+    return bs->alloc_cb.video ? bs->alloc_cb.video(ctx, bs->alloc_v, w, h) :
+        ff_default_get_video_buffer(link, w, h);
+}
+
+void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v)
+{
+    BufferSinkContext * const bs = ctx->priv;
+    bs->alloc_cb.video = cb;
+    bs->alloc_v = v;
+}
+
 static av_cold int common_init(AVFilterContext *ctx)
 {
     BufferSinkContext *buf = ctx->priv;
@@ -381,6 +401,7 @@  static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
     {
         .name = "default",
         .type = AVMEDIA_TYPE_VIDEO,
+        .get_buffer = {.video = alloc_video_buffer},
     },
 };
 
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index 64e08de53e..73f0ddc476 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -166,6 +166,33 @@  int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame);
  */
 int av_buffersink_get_samples(AVFilterContext *ctx, AVFrame *frame, int nb_samples);
 
+/**
+ * Callback from av_buffersink_set_alloc_video_frame to allocate 
+ * a frame 
+ *  
+ * @param ctx pointer to a context of the abuffersink AVFilter.
+ * @param v opaque pointer passed to 
+ *          av_buffersink_set_alloc_video_frame
+ * @param w width of frame to allocate 
+ * @param height of frame to allocate 
+ *  
+ * @return 
+ *         - The newly allocated frame
+ *         - NULL if error
+ */
+typedef AVFrame * av_buffersink_alloc_video_frame(AVFilterContext * ctx, void * v, int w, int h);
+
+/**
+ * Set a video frame allocation method for buffersink
+ *
+ * @param ctx pointer to a context of the abuffersink AVFilter.
+ * @param cb Callback to the allocation function. If set to NULL 
+ *           then the default avfilter allocation function will
+ *           be used.
+ * @param v  Opaque to pass to the allocation function
+ */
+void av_buffersink_set_alloc_video_frame(AVFilterContext *ctx, av_buffersink_alloc_video_frame * cb, void * v);
+
 /**
  * @}
  */
diff --git a/libavfilter/version.h b/libavfilter/version.h
index c001693e3c..54950497be 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -31,7 +31,7 @@ 
 
 #include "version_major.h"
 
-#define LIBAVFILTER_VERSION_MINOR   8
+#define LIBAVFILTER_VERSION_MINOR   9
 #define LIBAVFILTER_VERSION_MICRO 102