diff mbox series

[FFmpeg-devel,v20,10/20] avfilter/avfilter: Handle subtitle frames

Message ID DM8P223MB0365F6D3BBE1838D6DD7EA92BA6C9@DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM
State Superseded, archived
Headers show
Series [FFmpeg-devel,v20,01/20] avcodec, avutil: Move enum AVSubtitleType to avutil, add new and deprecate old values
Related show

Checks

Context Check Description
andriy/configurex86 warning Failed to apply patch
andriy/configureppc warning Failed to apply patch

Commit Message

Soft Works Dec. 5, 2021, 4:23 p.m. UTC
Signed-off-by: softworkz <softworkz@hotmail.com>
---
 doc/APIchanges              |  3 +++
 libavfilter/avfilter.c      |  8 +++++---
 libavfilter/avfilter.h      | 11 +++++++++++
 libavfilter/avfiltergraph.c |  5 +++++
 libavfilter/formats.c       | 22 ++++++++++++++++++++++
 libavfilter/formats.h       |  3 +++
 libavfilter/internal.h      | 18 +++++++++++++++---
 7 files changed, 64 insertions(+), 6 deletions(-)

Comments

Andreas Rheinhardt Dec. 5, 2021, 5:45 p.m. UTC | #1
Soft Works:
> Signed-off-by: softworkz <softworkz@hotmail.com>
> ---
>  doc/APIchanges              |  3 +++
>  libavfilter/avfilter.c      |  8 +++++---
>  libavfilter/avfilter.h      | 11 +++++++++++
>  libavfilter/avfiltergraph.c |  5 +++++
>  libavfilter/formats.c       | 22 ++++++++++++++++++++++
>  libavfilter/formats.h       |  3 +++
>  libavfilter/internal.h      | 18 +++++++++++++++---
>  7 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 83ac64c3f1..f695efe9ab 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -14,6 +14,9 @@ libavutil:     2021-04-27
>  
>  API changes, most recent first:
>  
> +2021-12-05 - xxxxxxxxxx - lavc 9.1.100 - avfilter.h
> +  Add fields subs_list and sub_fmt to AVFilter struct
> +

This is not public API, so don't make an APIchanges entry.

>  2021-12-05 - xxxxxxxxxx - lavc 60.1.100 - avcodec.h
>    Deprecate avcodec_encode_subtitle(), use regular encode api now
>  
> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
> index df5b8f483c..75d5e86539 100644
> --- a/libavfilter/avfilter.c
> +++ b/libavfilter/avfilter.c
> @@ -56,7 +56,8 @@ static void tlog_ref(void *ctx, AVFrame *ref, int end)
>              ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
>              ref->pts, ref->pkt_pos);
>  
> -    if (ref->width) {
> +    switch(ref->type) {
> +    case AVMEDIA_TYPE_VIDEO:
>          ff_tlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
>                  ref->sample_aspect_ratio.num, ref->sample_aspect_ratio.den,
>                  ref->width, ref->height,
> @@ -64,12 +65,13 @@ static void tlog_ref(void *ctx, AVFrame *ref, int end)
>                  ref->top_field_first ? 'T' : 'B',    /* Top / Bottom */
>                  ref->key_frame,
>                  av_get_picture_type_char(ref->pict_type));
> -    }
> -    if (ref->nb_samples) {
> +        break;
> +    case AVMEDIA_TYPE_AUDIO:
>          ff_tlog(ctx, " cl:%"PRId64"d n:%d r:%d",
>                  ref->channel_layout,
>                  ref->nb_samples,
>                  ref->sample_rate);
> +        break;
>      }
>  
>      ff_tlog(ctx, "]%s", end ? "\n" : "");
> diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
> index b105dc3159..9f917deb41 100644
> --- a/libavfilter/avfilter.h
> +++ b/libavfilter/avfilter.h
> @@ -45,6 +45,7 @@
>  #include "libavutil/log.h"
>  #include "libavutil/samplefmt.h"
>  #include "libavutil/pixfmt.h"
> +#include "libavutil/subfmt.h"
>  #include "libavutil/rational.h"
>  
>  #include "libavfilter/version.h"
> @@ -343,6 +344,12 @@ typedef struct AVFilter {
>           * and outputs use the same sample rate and channel count/layout.
>           */
>          const enum AVSampleFormat *samples_list;
> +        /**
> +         * Analogous to pixels, but delimited by AV_SUBTITLE_FMT_NONE
> +         * and restricted to filters that only have AVMEDIA_TYPE_SUBTITLE
> +         * inputs and outputs.
> +         */
> +        const enum AVSubtitleType *subs_list;
>          /**
>           * Equivalent to { pix_fmt, AV_PIX_FMT_NONE } as pixels_list.
>           */
> @@ -351,6 +358,10 @@ typedef struct AVFilter {
>           * Equivalent to { sample_fmt, AV_SAMPLE_FMT_NONE } as samples_list.
>           */
>          enum AVSampleFormat sample_fmt;
> +        /**
> +         * Equivalent to { sub_fmt, AV_SUBTITLE_FMT_NONE } as subs_list.
> +         */
> +        enum AVSubtitleType sub_fmt;
>      } formats;
>  
>      int priv_size;      ///< size of private data to allocate for the filter
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index b8b432e98b..f4987654af 100644
> --- a/libavfilter/avfiltergraph.c
> +++ b/libavfilter/avfiltergraph.c
> @@ -311,6 +311,8 @@ static int filter_link_check_formats(void *log, AVFilterLink *link, AVFilterForm
>              return ret;
>          break;
>  
> +    case AVMEDIA_TYPE_SUBTITLE:
> +        return 0;
>      default:
>          av_assert0(!"reached");
>      }
> @@ -441,6 +443,9 @@ static int query_formats(AVFilterGraph *graph, void *log_ctx)
>              if (!link)
>                  continue;
>  
> +            if (link->type == AVMEDIA_TYPE_SUBTITLE)
> +                continue;
> +
>              neg = ff_filter_get_negotiation(link);
>              av_assert0(neg);
>              for (neg_step = 1; neg_step < neg->nb_mergers; neg_step++) {
> diff --git a/libavfilter/formats.c b/libavfilter/formats.c
> index ba62f73248..46dbbd2975 100644
> --- a/libavfilter/formats.c
> +++ b/libavfilter/formats.c
> @@ -19,6 +19,7 @@
>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>   */
>  
> +#include "libavcodec/avcodec.h"

libavutil/subfmt.h, I presume?

>  #include "libavutil/avassert.h"
>  #include "libavutil/channel_layout.h"
>  #include "libavutil/common.h"
> @@ -431,6 +432,12 @@ int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
>      return 0;
>  }
>  
> +int ff_add_subtitle_type(AVFilterFormats **avff, int64_t fmt)
> +{
> +    ADD_FORMAT(avff, fmt, ff_formats_unref, int, formats, nb_formats);
> +    return 0;
> +}
> +
>  AVFilterFormats *ff_make_formats_list_singleton(int fmt)
>  {
>      int fmts[2] = { fmt, -1 };
> @@ -450,6 +457,13 @@ AVFilterFormats *ff_all_formats(enum AVMediaType type)
>                  return NULL;
>              fmt++;
>          }
> +    } else if (type == AVMEDIA_TYPE_SUBTITLE) {
> +        if (ff_add_subtitle_type(&ret, AV_SUBTITLE_FMT_BITMAP) < 0)
> +            return NULL;
> +        if (ff_add_subtitle_type(&ret, AV_SUBTITLE_FMT_ASS) < 0)
> +            return NULL;
> +        if (ff_add_subtitle_type(&ret, AV_SUBTITLE_FMT_TEXT) < 0)
> +            return NULL;
>      }
>  
>      return ret;
> @@ -724,6 +738,10 @@ int ff_default_query_formats(AVFilterContext *ctx)
>          type    = AVMEDIA_TYPE_AUDIO;
>          formats = ff_make_format_list(f->formats.samples_list);
>          break;
> +    case FF_FILTER_FORMATS_SUBFMTS_LIST:
> +        type    = AVMEDIA_TYPE_SUBTITLE;
> +        formats = ff_make_format_list(f->formats.subs_list);
> +        break;
>      case FF_FILTER_FORMATS_SINGLE_PIXFMT:
>          type    = AVMEDIA_TYPE_VIDEO;
>          formats = ff_make_formats_list_singleton(f->formats.pix_fmt);
> @@ -732,6 +750,10 @@ int ff_default_query_formats(AVFilterContext *ctx)
>          type    = AVMEDIA_TYPE_AUDIO;
>          formats = ff_make_formats_list_singleton(f->formats.sample_fmt);
>          break;
> +    case FF_FILTER_FORMATS_SINGLE_SUBFMT:
> +        type    = AVMEDIA_TYPE_SUBTITLE;
> +        formats = ff_make_formats_list_singleton(f->formats.sub_fmt);
> +        break;
>      default:
>          av_assert2(!"Unreachable");
>      /* Intended fallthrough */
> diff --git a/libavfilter/formats.h b/libavfilter/formats.h
> index a884d15213..94754ebd88 100644
> --- a/libavfilter/formats.h
> +++ b/libavfilter/formats.h
> @@ -180,6 +180,9 @@ int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts);
>  av_warn_unused_result
>  int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
>  
> +av_warn_unused_result
> +int ff_add_subtitle_type(AVFilterFormats **avff, int64_t fmt);
> +
>  /**
>   * Add *ref as a new reference to f.
>   */
> diff --git a/libavfilter/internal.h b/libavfilter/internal.h
> index fc09ef574c..192b0ae196 100644
> --- a/libavfilter/internal.h
> +++ b/libavfilter/internal.h
> @@ -149,9 +149,11 @@ static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_act
>  
>  enum FilterFormatsState {
>      /**
> -     * The default value meaning that this filter supports all formats
> -     * and (for audio) sample rates and channel layouts/counts as long
> -     * as these properties agree for all inputs and outputs.
> +     * The default value meaning that this filter supports
> +     * - For video:     all formats
> +     * - For audio:     all sample rates and channel layouts/counts
> +     * - For subtitles: all subtitle formats
> +     * as long as these properties agree for all inputs and outputs.
>       * This state is only allowed in case all inputs and outputs actually
>       * have the same type.
>       * The union is unused in this state.
> @@ -162,8 +164,10 @@ enum FilterFormatsState {
>      FF_FILTER_FORMATS_QUERY_FUNC,       ///< formats.query active.
>      FF_FILTER_FORMATS_PIXFMT_LIST,      ///< formats.pixels_list active.
>      FF_FILTER_FORMATS_SAMPLEFMTS_LIST,  ///< formats.samples_list active.
> +    FF_FILTER_FORMATS_SUBFMTS_LIST,     ///< formats.subs_list active.
>      FF_FILTER_FORMATS_SINGLE_PIXFMT,    ///< formats.pix_fmt active
>      FF_FILTER_FORMATS_SINGLE_SAMPLEFMT, ///< formats.sample_fmt active.
> +    FF_FILTER_FORMATS_SINGLE_SUBFMT,    ///< formats.sub_fmt active.
>  };
>  
>  #define FILTER_QUERY_FUNC(func)        \
> @@ -175,16 +179,24 @@ enum FilterFormatsState {
>  #define FILTER_SAMPLEFMTS_ARRAY(array) \
>          .formats.samples_list = array, \
>          .formats_state        = FF_FILTER_FORMATS_SAMPLEFMTS_LIST
> +#define FILTER_SUBFMTS_ARRAY(array) \
> +        .formats.subs_list = array, \
> +        .formats_state        = FF_FILTER_FORMATS_SUBFMTS_LIST
>  #define FILTER_PIXFMTS(...)            \
>      FILTER_PIXFMTS_ARRAY(((const enum AVPixelFormat []) { __VA_ARGS__, AV_PIX_FMT_NONE }))
>  #define FILTER_SAMPLEFMTS(...)         \
>      FILTER_SAMPLEFMTS_ARRAY(((const enum AVSampleFormat[]) { __VA_ARGS__, AV_SAMPLE_FMT_NONE }))
> +#define FILTER_SUBFMTS(...)         \
> +    FILTER_SUBFMTS_ARRAY(((const enum AVSubtitleType[]) { __VA_ARGS__, AV_SUBTITLE_FMT_NONE }))
>  #define FILTER_SINGLE_PIXFMT(pix_fmt_)  \
>          .formats.pix_fmt = pix_fmt_,    \
>          .formats_state   = FF_FILTER_FORMATS_SINGLE_PIXFMT
>  #define FILTER_SINGLE_SAMPLEFMT(sample_fmt_) \
>          .formats.sample_fmt = sample_fmt_,   \
>          .formats_state      = FF_FILTER_FORMATS_SINGLE_SAMPLEFMT
> +#define FILTER_SINGLE_SUBFMT(sub_fmt_) \
> +        .formats.sub_fmt = sub_fmt_,   \
> +        .formats_state      = FF_FILTER_FORMATS_SINGLE_SUBFMT
>  
>  #define FILTER_INOUTPADS(inout, array) \
>         .inout        = array, \
>
diff mbox series

Patch

diff --git a/doc/APIchanges b/doc/APIchanges
index 83ac64c3f1..f695efe9ab 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -14,6 +14,9 @@  libavutil:     2021-04-27
 
 API changes, most recent first:
 
+2021-12-05 - xxxxxxxxxx - lavc 9.1.100 - avfilter.h
+  Add fields subs_list and sub_fmt to AVFilter struct
+
 2021-12-05 - xxxxxxxxxx - lavc 60.1.100 - avcodec.h
   Deprecate avcodec_encode_subtitle(), use regular encode api now
 
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index df5b8f483c..75d5e86539 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -56,7 +56,8 @@  static void tlog_ref(void *ctx, AVFrame *ref, int end)
             ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
             ref->pts, ref->pkt_pos);
 
-    if (ref->width) {
+    switch(ref->type) {
+    case AVMEDIA_TYPE_VIDEO:
         ff_tlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
                 ref->sample_aspect_ratio.num, ref->sample_aspect_ratio.den,
                 ref->width, ref->height,
@@ -64,12 +65,13 @@  static void tlog_ref(void *ctx, AVFrame *ref, int end)
                 ref->top_field_first ? 'T' : 'B',    /* Top / Bottom */
                 ref->key_frame,
                 av_get_picture_type_char(ref->pict_type));
-    }
-    if (ref->nb_samples) {
+        break;
+    case AVMEDIA_TYPE_AUDIO:
         ff_tlog(ctx, " cl:%"PRId64"d n:%d r:%d",
                 ref->channel_layout,
                 ref->nb_samples,
                 ref->sample_rate);
+        break;
     }
 
     ff_tlog(ctx, "]%s", end ? "\n" : "");
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index b105dc3159..9f917deb41 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -45,6 +45,7 @@ 
 #include "libavutil/log.h"
 #include "libavutil/samplefmt.h"
 #include "libavutil/pixfmt.h"
+#include "libavutil/subfmt.h"
 #include "libavutil/rational.h"
 
 #include "libavfilter/version.h"
@@ -343,6 +344,12 @@  typedef struct AVFilter {
          * and outputs use the same sample rate and channel count/layout.
          */
         const enum AVSampleFormat *samples_list;
+        /**
+         * Analogous to pixels, but delimited by AV_SUBTITLE_FMT_NONE
+         * and restricted to filters that only have AVMEDIA_TYPE_SUBTITLE
+         * inputs and outputs.
+         */
+        const enum AVSubtitleType *subs_list;
         /**
          * Equivalent to { pix_fmt, AV_PIX_FMT_NONE } as pixels_list.
          */
@@ -351,6 +358,10 @@  typedef struct AVFilter {
          * Equivalent to { sample_fmt, AV_SAMPLE_FMT_NONE } as samples_list.
          */
         enum AVSampleFormat sample_fmt;
+        /**
+         * Equivalent to { sub_fmt, AV_SUBTITLE_FMT_NONE } as subs_list.
+         */
+        enum AVSubtitleType sub_fmt;
     } formats;
 
     int priv_size;      ///< size of private data to allocate for the filter
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index b8b432e98b..f4987654af 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -311,6 +311,8 @@  static int filter_link_check_formats(void *log, AVFilterLink *link, AVFilterForm
             return ret;
         break;
 
+    case AVMEDIA_TYPE_SUBTITLE:
+        return 0;
     default:
         av_assert0(!"reached");
     }
@@ -441,6 +443,9 @@  static int query_formats(AVFilterGraph *graph, void *log_ctx)
             if (!link)
                 continue;
 
+            if (link->type == AVMEDIA_TYPE_SUBTITLE)
+                continue;
+
             neg = ff_filter_get_negotiation(link);
             av_assert0(neg);
             for (neg_step = 1; neg_step < neg->nb_mergers; neg_step++) {
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index ba62f73248..46dbbd2975 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -19,6 +19,7 @@ 
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavcodec/avcodec.h"
 #include "libavutil/avassert.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
@@ -431,6 +432,12 @@  int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
     return 0;
 }
 
+int ff_add_subtitle_type(AVFilterFormats **avff, int64_t fmt)
+{
+    ADD_FORMAT(avff, fmt, ff_formats_unref, int, formats, nb_formats);
+    return 0;
+}
+
 AVFilterFormats *ff_make_formats_list_singleton(int fmt)
 {
     int fmts[2] = { fmt, -1 };
@@ -450,6 +457,13 @@  AVFilterFormats *ff_all_formats(enum AVMediaType type)
                 return NULL;
             fmt++;
         }
+    } else if (type == AVMEDIA_TYPE_SUBTITLE) {
+        if (ff_add_subtitle_type(&ret, AV_SUBTITLE_FMT_BITMAP) < 0)
+            return NULL;
+        if (ff_add_subtitle_type(&ret, AV_SUBTITLE_FMT_ASS) < 0)
+            return NULL;
+        if (ff_add_subtitle_type(&ret, AV_SUBTITLE_FMT_TEXT) < 0)
+            return NULL;
     }
 
     return ret;
@@ -724,6 +738,10 @@  int ff_default_query_formats(AVFilterContext *ctx)
         type    = AVMEDIA_TYPE_AUDIO;
         formats = ff_make_format_list(f->formats.samples_list);
         break;
+    case FF_FILTER_FORMATS_SUBFMTS_LIST:
+        type    = AVMEDIA_TYPE_SUBTITLE;
+        formats = ff_make_format_list(f->formats.subs_list);
+        break;
     case FF_FILTER_FORMATS_SINGLE_PIXFMT:
         type    = AVMEDIA_TYPE_VIDEO;
         formats = ff_make_formats_list_singleton(f->formats.pix_fmt);
@@ -732,6 +750,10 @@  int ff_default_query_formats(AVFilterContext *ctx)
         type    = AVMEDIA_TYPE_AUDIO;
         formats = ff_make_formats_list_singleton(f->formats.sample_fmt);
         break;
+    case FF_FILTER_FORMATS_SINGLE_SUBFMT:
+        type    = AVMEDIA_TYPE_SUBTITLE;
+        formats = ff_make_formats_list_singleton(f->formats.sub_fmt);
+        break;
     default:
         av_assert2(!"Unreachable");
     /* Intended fallthrough */
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index a884d15213..94754ebd88 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -180,6 +180,9 @@  int ff_set_common_formats_from_list(AVFilterContext *ctx, const int *fmts);
 av_warn_unused_result
 int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
 
+av_warn_unused_result
+int ff_add_subtitle_type(AVFilterFormats **avff, int64_t fmt);
+
 /**
  * Add *ref as a new reference to f.
  */
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index fc09ef574c..192b0ae196 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -149,9 +149,11 @@  static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_act
 
 enum FilterFormatsState {
     /**
-     * The default value meaning that this filter supports all formats
-     * and (for audio) sample rates and channel layouts/counts as long
-     * as these properties agree for all inputs and outputs.
+     * The default value meaning that this filter supports
+     * - For video:     all formats
+     * - For audio:     all sample rates and channel layouts/counts
+     * - For subtitles: all subtitle formats
+     * as long as these properties agree for all inputs and outputs.
      * This state is only allowed in case all inputs and outputs actually
      * have the same type.
      * The union is unused in this state.
@@ -162,8 +164,10 @@  enum FilterFormatsState {
     FF_FILTER_FORMATS_QUERY_FUNC,       ///< formats.query active.
     FF_FILTER_FORMATS_PIXFMT_LIST,      ///< formats.pixels_list active.
     FF_FILTER_FORMATS_SAMPLEFMTS_LIST,  ///< formats.samples_list active.
+    FF_FILTER_FORMATS_SUBFMTS_LIST,     ///< formats.subs_list active.
     FF_FILTER_FORMATS_SINGLE_PIXFMT,    ///< formats.pix_fmt active
     FF_FILTER_FORMATS_SINGLE_SAMPLEFMT, ///< formats.sample_fmt active.
+    FF_FILTER_FORMATS_SINGLE_SUBFMT,    ///< formats.sub_fmt active.
 };
 
 #define FILTER_QUERY_FUNC(func)        \
@@ -175,16 +179,24 @@  enum FilterFormatsState {
 #define FILTER_SAMPLEFMTS_ARRAY(array) \
         .formats.samples_list = array, \
         .formats_state        = FF_FILTER_FORMATS_SAMPLEFMTS_LIST
+#define FILTER_SUBFMTS_ARRAY(array) \
+        .formats.subs_list = array, \
+        .formats_state        = FF_FILTER_FORMATS_SUBFMTS_LIST
 #define FILTER_PIXFMTS(...)            \
     FILTER_PIXFMTS_ARRAY(((const enum AVPixelFormat []) { __VA_ARGS__, AV_PIX_FMT_NONE }))
 #define FILTER_SAMPLEFMTS(...)         \
     FILTER_SAMPLEFMTS_ARRAY(((const enum AVSampleFormat[]) { __VA_ARGS__, AV_SAMPLE_FMT_NONE }))
+#define FILTER_SUBFMTS(...)         \
+    FILTER_SUBFMTS_ARRAY(((const enum AVSubtitleType[]) { __VA_ARGS__, AV_SUBTITLE_FMT_NONE }))
 #define FILTER_SINGLE_PIXFMT(pix_fmt_)  \
         .formats.pix_fmt = pix_fmt_,    \
         .formats_state   = FF_FILTER_FORMATS_SINGLE_PIXFMT
 #define FILTER_SINGLE_SAMPLEFMT(sample_fmt_) \
         .formats.sample_fmt = sample_fmt_,   \
         .formats_state      = FF_FILTER_FORMATS_SINGLE_SAMPLEFMT
+#define FILTER_SINGLE_SUBFMT(sub_fmt_) \
+        .formats.sub_fmt = sub_fmt_,   \
+        .formats_state      = FF_FILTER_FORMATS_SINGLE_SUBFMT
 
 #define FILTER_INOUTPADS(inout, array) \
        .inout        = array, \