Merge commit 'b01f6041f4260fba053c2f96ce1611ea77e833a0'
authorMichael Niedermayer <michaelni@gmx.at>
Sat, 18 May 2013 09:40:38 +0000 (11:40 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 18 May 2013 09:46:09 +0000 (11:46 +0200)
* commit 'b01f6041f4260fba053c2f96ce1611ea77e833a0':
  lavfi: rename AVFilterFormats.format_count to nb_formats

Conflicts:
libavfilter/avfiltergraph.c
libavfilter/filtfmts.c
libavfilter/formats.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavfilter/avfiltergraph.c
libavfilter/filtfmts.c
libavfilter/formats.c
libavfilter/formats.h
libavfilter/vf_extractplanes.c
libavfilter/vf_format.c

@@@ -498,23 -341,7 +498,23 @@@ static int pick_format(AVFilterLink *li
      if (!link || !link->in_formats)
          return 0;
  
-             for (i=0; i<link->in_formats->format_count; i++) {
 +    if (link->type == AVMEDIA_TYPE_VIDEO) {
 +        if(ref && ref->type == AVMEDIA_TYPE_VIDEO){
 +            int has_alpha= av_pix_fmt_desc_get(ref->format)->nb_components % 2 == 0;
 +            enum AVPixelFormat best= AV_PIX_FMT_NONE;
 +            int i;
-                    av_get_pix_fmt_name(best), link->in_formats->format_count,
++            for (i=0; i<link->in_formats->nb_formats; i++) {
 +                enum AVPixelFormat p = link->in_formats->formats[i];
 +                best= avcodec_find_best_pix_fmt_of_2(best, p, ref->format, has_alpha, NULL);
 +            }
 +            av_log(link->src,AV_LOG_DEBUG, "picking %s out of %d ref:%s alpha:%d\n",
-     link->in_formats->format_count = 1;
++                   av_get_pix_fmt_name(best), link->in_formats->nb_formats,
 +                   av_get_pix_fmt_name(ref->format), has_alpha);
 +            link->in_formats->formats[0] = best;
 +        }
 +    }
 +
+     link->in_formats->nb_formats = 1;
      link->format = link->in_formats->formats[0];
  
      if (link->type == AVMEDIA_TYPE_AUDIO) {
                     link->dst->name);
              return AVERROR(EINVAL);
          }
-         link->in_samplerates->format_count = 1;
+         link->in_samplerates->nb_formats = 1;
          link->sample_rate = link->in_samplerates->formats[0];
  
 -        if (!link->in_channel_layouts->nb_channel_layouts) {
 +        if (link->in_channel_layouts->all_layouts) {
              av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for"
 -                   "the link between filters %s and %s.\n", link->src->name,
 +                   " the link between filters %s and %s.\n", link->src->name,
                     link->dst->name);
              return AVERROR(EINVAL);
          }
@@@ -591,45 -414,11 +591,45 @@@ static int reduce_formats_on_filter(AVF
      int i, j, k, ret = 0;
  
      REDUCE_FORMATS(int,      AVFilterFormats,        formats,         formats,
-                    format_count, ff_add_format);
+                    nb_formats, ff_add_format);
      REDUCE_FORMATS(int,      AVFilterFormats,        samplerates,     formats,
-                    format_count, ff_add_format);
+                    nb_formats, ff_add_format);
 -    REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts,
 -                   channel_layouts, nb_channel_layouts, ff_add_channel_layout);
 +
 +    /* reduce channel layouts */
 +    for (i = 0; i < filter->nb_inputs; i++) {
 +        AVFilterLink *inlink = filter->inputs[i];
 +        uint64_t fmt;
 +
 +        if (!inlink->out_channel_layouts ||
 +            inlink->out_channel_layouts->nb_channel_layouts != 1)
 +            continue;
 +        fmt = inlink->out_channel_layouts->channel_layouts[0];
 +
 +        for (j = 0; j < filter->nb_outputs; j++) {
 +            AVFilterLink *outlink = filter->outputs[j];
 +            AVFilterChannelLayouts *fmts;
 +
 +            fmts = outlink->in_channel_layouts;
 +            if (inlink->type != outlink->type || fmts->nb_channel_layouts == 1)
 +                continue;
 +
 +            if (fmts->all_layouts) {
 +                /* Turn the infinite list into a singleton */
 +                fmts->all_layouts = fmts->all_counts  = 0;
 +                ff_add_channel_layout(&outlink->in_channel_layouts, fmt);
 +                break;
 +            }
 +
 +            for (k = 0; k < outlink->in_channel_layouts->nb_channel_layouts; k++) {
 +                if (fmts->channel_layouts[k] == fmt) {
 +                    fmts->channel_layouts[0]  = fmt;
 +                    fmts->nb_channel_layouts = 1;
 +                    ret = 1;
 +                    break;
 +                }
 +            }
 +        }
 +    }
  
      return ret;
  }
@@@ -896,41 -669,6 +896,41 @@@ static void swap_sample_fmts(AVFilterGr
  static int pick_formats(AVFilterGraph *graph)
  {
      int i, j, ret;
-                     if(filter->inputs[j]->in_formats && filter->inputs[j]->in_formats->format_count == 1) {
 +    int change;
 +
 +    do{
 +        change = 0;
 +        for (i = 0; i < graph->nb_filters; i++) {
 +            AVFilterContext *filter = graph->filters[i];
 +            if (filter->nb_inputs){
 +                for (j = 0; j < filter->nb_inputs; j++){
-                     if(filter->outputs[j]->in_formats && filter->outputs[j]->in_formats->format_count == 1) {
++                    if(filter->inputs[j]->in_formats && filter->inputs[j]->in_formats->nb_formats == 1) {
 +                        if ((ret = pick_format(filter->inputs[j], NULL)) < 0)
 +                            return ret;
 +                        change = 1;
 +                    }
 +                }
 +            }
 +            if (filter->nb_outputs){
 +                for (j = 0; j < filter->nb_outputs; j++){
++                    if(filter->outputs[j]->in_formats && filter->outputs[j]->in_formats->nb_formats == 1) {
 +                        if ((ret = pick_format(filter->outputs[j], NULL)) < 0)
 +                            return ret;
 +                        change = 1;
 +                    }
 +                }
 +            }
 +            if (filter->nb_inputs && filter->nb_outputs && filter->inputs[0]->format>=0) {
 +                for (j = 0; j < filter->nb_outputs; j++) {
 +                    if(filter->outputs[j]->format<0) {
 +                        if ((ret = pick_format(filter->outputs[j], filter->inputs[0])) < 0)
 +                            return ret;
 +                        change = 1;
 +                    }
 +                }
 +            }
 +        }
 +    }while(change);
  
      for (i = 0; i < graph->nb_filters; i++) {
          AVFilterContext *filter = graph->filters[i];
  #include "libavfilter/avfilter.h"
  #include "libavfilter/formats.h"
  
-             for (j = 0; j < fmts->format_count; j++)                    \
 +static void print_formats(AVFilterContext *filter_ctx)
 +{
 +    int i, j;
 +
 +#define PRINT_FMTS(inout, outin, INOUT)                                 \
 +    for (i = 0; i < filter_ctx->inout##put_count; i++) {                     \
 +        if (filter_ctx->inout##puts[i]->type == AVMEDIA_TYPE_VIDEO) {   \
 +            AVFilterFormats *fmts =                                     \
 +                filter_ctx->inout##puts[i]->outin##_formats;            \
-             for (j = 0; j < fmts->format_count; j++)                    \
++            for (j = 0; j < fmts->nb_formats; j++)                    \
 +                if(av_get_pix_fmt_name(fmts->formats[j]))               \
 +                printf(#INOUT "PUT[%d] %s: fmt:%s\n",                   \
 +                       i, filter_ctx->filter->inout##puts[i].name,      \
 +                       av_get_pix_fmt_name(fmts->formats[j]));          \
 +        } else if (filter_ctx->inout##puts[i]->type == AVMEDIA_TYPE_AUDIO) { \
 +            AVFilterFormats *fmts;                                      \
 +            AVFilterChannelLayouts *layouts;                            \
 +                                                                        \
 +            fmts = filter_ctx->inout##puts[i]->outin##_formats;         \
++            for (j = 0; j < fmts->nb_formats; j++)                    \
 +                printf(#INOUT "PUT[%d] %s: fmt:%s\n",                   \
 +                       i, filter_ctx->filter->inout##puts[i].name,      \
 +                       av_get_sample_fmt_name(fmts->formats[j]));       \
 +                                                                        \
 +            layouts = filter_ctx->inout##puts[i]->outin##_channel_layouts; \
 +            for (j = 0; j < layouts->nb_channel_layouts; j++) {                  \
 +                char buf[256];                                          \
 +                av_get_channel_layout_string(buf, sizeof(buf), -1,      \
 +                                             layouts->channel_layouts[j]);         \
 +                printf(#INOUT "PUT[%d] %s: chlayout:%s\n",              \
 +                       i, filter_ctx->filter->inout##puts[i].name, buf); \
 +            }                                                           \
 +        }                                                               \
 +    }                                                                   \
 +
 +    PRINT_FMTS(in,  out, IN);
 +    PRINT_FMTS(out, in,  OUT);
 +}
 +
  int main(int argc, char **argv)
  {
      AVFilter *filter;
@@@ -100,31 -84,7 +100,31 @@@ AVFilterFormats *ff_merge_formats(AVFil
      if (a == b)
          return a;
  
-         for (i = 0; i < a->format_count; i++)
-             for (j = 0; j < b->format_count; j++) {
 +    /* Do not lose chroma or alpha in merging.
 +       It happens if both lists have formats with chroma (resp. alpha), but
 +       the only formats in common do not have it (e.g. YUV+gray vs.
 +       RGB+gray): in that case, the merging would select the gray format,
 +       possibly causing a lossy conversion elsewhere in the graph.
 +       To avoid that, pretend that there are no common formats to force the
 +       insertion of a conversion filter. */
 +    if (type == AVMEDIA_TYPE_VIDEO)
-     MERGE_FORMATS(ret, a, b, formats, format_count, AVFilterFormats, fail);
++        for (i = 0; i < a->nb_formats; i++)
++            for (j = 0; j < b->nb_formats; j++) {
 +                const AVPixFmtDescriptor *adesc = av_pix_fmt_desc_get(a->formats[i]);
 +                const AVPixFmtDescriptor *bdesc = av_pix_fmt_desc_get(b->formats[j]);
 +                alpha2 |= adesc->flags & bdesc->flags & AV_PIX_FMT_FLAG_ALPHA;
 +                chroma2|= adesc->nb_components > 1 && bdesc->nb_components > 1;
 +                if (a->formats[i] == b->formats[j]) {
 +                    alpha1 |= adesc->flags & AV_PIX_FMT_FLAG_ALPHA;
 +                    chroma1|= adesc->nb_components > 1;
 +                }
 +            }
 +
 +    // If chroma or alpha can be lost through merging then do not merge
 +    if (alpha2 > alpha1 || chroma2 > chroma1)
 +        return NULL;
 +
+     MERGE_FORMATS(ret, a, b, formats, nb_formats, AVFilterFormats, fail);
  
      return ret;
  fail:
@@@ -262,65 -162,19 +262,65 @@@ int ff_fmt_is_in(int fmt, const int *fm
      return 0;
  }
  
 +#define COPY_INT_LIST(list_copy, list, type) {                          \
 +    int count = 0;                                                      \
 +    if (list)                                                           \
 +        for (count = 0; list[count] != -1; count++)                     \
 +            ;                                                           \
 +    list_copy = av_calloc(count+1, sizeof(type));                       \
 +    if (list_copy) {                                                    \
 +        memcpy(list_copy, list, sizeof(type) * count);                  \
 +        list_copy[count] = -1;                                          \
 +    }                                                                   \
 +}
 +
 +int *ff_copy_int_list(const int * const list)
 +{
 +    int *ret = NULL;
 +    COPY_INT_LIST(ret, list, int);
 +    return ret;
 +}
 +
 +int64_t *ff_copy_int64_list(const int64_t * const list)
 +{
 +    int64_t *ret = NULL;
 +    COPY_INT_LIST(ret, list, int64_t);
 +    return ret;
 +}
 +
 +#define MAKE_FORMAT_LIST(type, field, count_field)                      \
 +    type *formats;                                                      \
 +    int count = 0;                                                      \
 +    if (fmts)                                                           \
 +        for (count = 0; fmts[count] != -1; count++)                     \
 +            ;                                                           \
 +    formats = av_mallocz(sizeof(*formats));                             \
 +    if (!formats) return NULL;                                          \
 +    formats->count_field = count;                                       \
 +    if (count) {                                                        \
 +        formats->field = av_malloc(sizeof(*formats->field)*count);      \
 +        if (!formats->field) {                                          \
 +            av_free(formats);                                           \
 +            return NULL;                                                \
 +        }                                                               \
 +    }
 +
  AVFilterFormats *ff_make_format_list(const int *fmts)
  {
-     MAKE_FORMAT_LIST(AVFilterFormats, formats, format_count);
 -    AVFilterFormats *formats;
 -    int count;
++    MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
 +    while (count--)
 +        formats->formats[count] = fmts[count];
  
 -    for (count = 0; fmts[count] != -1; count++)
 -        ;
 +    return formats;
 +}
  
 -    formats               = av_mallocz(sizeof(*formats));
 +AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts)
 +{
 +    MAKE_FORMAT_LIST(AVFilterChannelLayouts,
 +                     channel_layouts, nb_channel_layouts);
      if (count)
 -        formats->formats  = av_malloc(sizeof(*formats->formats) * count);
 -    formats->nb_formats = count;
 -    memcpy(formats->formats, fmts, sizeof(*formats->formats) * count);
 +        memcpy(formats->channel_layouts, fmts,
 +               sizeof(*formats->channel_layouts) * count);
  
      return formats;
  }
@@@ -339,12 -193,12 +339,12 @@@ do 
                                                              \
      (*f)->list = fmts;                                      \
      (*f)->list[(*f)->nb++] = fmt;                           \
 -    return 0;                                               \
  } while (0)
  
 -int ff_add_format(AVFilterFormats **avff, int fmt)
 +int ff_add_format(AVFilterFormats **avff, int64_t fmt)
  {
-     ADD_FORMAT(avff, fmt, int, formats, format_count);
+     ADD_FORMAT(avff, fmt, int, formats, nb_formats);
 +    return 0;
  }
  
  int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
Simple merge
index 3c629d7,0000000..52dffcc
mode 100644,000000..100644
--- /dev/null
@@@ -1,335 -1,0 +1,335 @@@
-         !ctx->inputs[0]->in_formats->format_count) {
 +/*
 + * Copyright (c) 2013 Paul B Mahol
 + *
 + * 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
 + */
 +
 +#include "libavutil/avstring.h"
 +#include "libavutil/imgutils.h"
 +#include "libavutil/opt.h"
 +#include "libavutil/pixdesc.h"
 +#include "avfilter.h"
 +#include "drawutils.h"
 +#include "internal.h"
 +
 +#define PLANE_R 0x01
 +#define PLANE_G 0x02
 +#define PLANE_B 0x04
 +#define PLANE_A 0x08
 +#define PLANE_Y 0x10
 +#define PLANE_U 0x20
 +#define PLANE_V 0x40
 +
 +typedef struct {
 +    const AVClass *class;
 +    int requested_planes;
 +    int map[4];
 +    int linesize[4];
 +    int is_packed_rgb;
 +    int depth;
 +    int step;
 +} ExtractPlanesContext;
 +
 +#define OFFSET(x) offsetof(ExtractPlanesContext, x)
 +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 +static const AVOption extractplanes_options[] = {
 +    { "planes", "set planes",  OFFSET(requested_planes), AV_OPT_TYPE_FLAGS, {.i64=1}, 1, 0xff, FLAGS, "flags"},
 +    {      "y", "set luma plane",  0, AV_OPT_TYPE_CONST, {.i64=PLANE_Y}, 0, 0, FLAGS, "flags"},
 +    {      "u", "set u plane",     0, AV_OPT_TYPE_CONST, {.i64=PLANE_U}, 0, 0, FLAGS, "flags"},
 +    {      "v", "set v plane",     0, AV_OPT_TYPE_CONST, {.i64=PLANE_V}, 0, 0, FLAGS, "flags"},
 +    {      "r", "set red plane",   0, AV_OPT_TYPE_CONST, {.i64=PLANE_R}, 0, 0, FLAGS, "flags"},
 +    {      "g", "set green plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_G}, 0, 0, FLAGS, "flags"},
 +    {      "b", "set blue plane",  0, AV_OPT_TYPE_CONST, {.i64=PLANE_B}, 0, 0, FLAGS, "flags"},
 +    {      "a", "set alpha plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_A}, 0, 0, FLAGS, "flags"},
 +    { NULL }
 +};
 +
 +AVFILTER_DEFINE_CLASS(extractplanes);
 +
 +static int query_formats(AVFilterContext *ctx)
 +{
 +    static const enum AVPixelFormat in_pixfmts[] = {
 +        AV_PIX_FMT_YUV410P,
 +        AV_PIX_FMT_YUV411P,
 +        AV_PIX_FMT_YUV440P,
 +        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
 +        AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P,
 +        AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
 +        AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
 +        AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P,
 +        AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUVA420P16LE,
 +        AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUVA420P16BE,
 +        AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUVA422P16LE,
 +        AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUVA422P16BE,
 +        AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUVA444P16LE,
 +        AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUVA444P16BE,
 +        AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
 +        AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE,
 +        AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
 +        AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
 +        AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
 +        AV_PIX_FMT_RGB48LE, AV_PIX_FMT_BGR48LE,
 +        AV_PIX_FMT_RGB48BE, AV_PIX_FMT_BGR48BE,
 +        AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_BGRA64LE,
 +        AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_BGRA64BE,
 +        AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
 +        AV_PIX_FMT_GBRP16LE, AV_PIX_FMT_GBRP16BE,
 +        AV_PIX_FMT_GBRAP16LE, AV_PIX_FMT_GBRAP16BE,
 +        AV_PIX_FMT_NONE,
 +    };
 +    static const enum AVPixelFormat out8_pixfmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
 +    static const enum AVPixelFormat out16le_pixfmts[] = { AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_NONE };
 +    static const enum AVPixelFormat out16be_pixfmts[] = { AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE };
 +    const enum AVPixelFormat *out_pixfmts;
 +    const AVPixFmtDescriptor *desc;
 +    AVFilterFormats *avff;
 +    int i, depth = 0, be = 0;
 +
 +    if (!ctx->inputs[0]->in_formats ||
-     for (i = 1; i < avff->format_count; i++) {
++        !ctx->inputs[0]->in_formats->nb_formats) {
 +        return AVERROR(EAGAIN);
 +    }
 +
 +    if (!ctx->inputs[0]->out_formats)
 +        ff_formats_ref(ff_make_format_list(in_pixfmts), &ctx->inputs[0]->out_formats);
 +
 +    avff = ctx->inputs[0]->in_formats;
 +    desc = av_pix_fmt_desc_get(avff->formats[0]);
 +    depth = desc->comp[0].depth_minus1;
 +    be = desc->flags & AV_PIX_FMT_FLAG_BE;
++    for (i = 1; i < avff->nb_formats; i++) {
 +        desc = av_pix_fmt_desc_get(avff->formats[i]);
 +        if (depth != desc->comp[0].depth_minus1 ||
 +            be    != (desc->flags & AV_PIX_FMT_FLAG_BE)) {
 +            return AVERROR(EAGAIN);
 +        }
 +    }
 +
 +    if (depth == 7)
 +        out_pixfmts = out8_pixfmts;
 +    else if (be)
 +        out_pixfmts = out16be_pixfmts;
 +    else
 +        out_pixfmts = out16le_pixfmts;
 +
 +    for (i = 0; i < ctx->nb_outputs; i++)
 +        ff_formats_ref(ff_make_format_list(out_pixfmts), &ctx->outputs[i]->in_formats);
 +    return 0;
 +}
 +
 +static int config_input(AVFilterLink *inlink)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    ExtractPlanesContext *e = ctx->priv;
 +    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
 +    int plane_avail, ret, i;
 +    uint8_t rgba_map[4];
 +
 +    plane_avail = ((desc->flags & AV_PIX_FMT_FLAG_RGB) ? PLANE_R|PLANE_G|PLANE_B :
 +                                                 PLANE_Y |
 +                                ((desc->nb_components > 2) ? PLANE_U|PLANE_V : 0)) |
 +                  ((desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? PLANE_A : 0);
 +    if (e->requested_planes & ~plane_avail) {
 +        av_log(ctx, AV_LOG_ERROR, "Requested planes not available.\n");
 +        return AVERROR(EINVAL);
 +    }
 +    if ((ret = av_image_fill_linesizes(e->linesize, inlink->format, inlink->w)) < 0)
 +        return ret;
 +
 +    e->depth = (desc->comp[0].depth_minus1 + 1) >> 3;
 +    e->step = av_get_padded_bits_per_pixel(desc) >> 3;
 +    e->is_packed_rgb = !(desc->flags & AV_PIX_FMT_FLAG_PLANAR);
 +    if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
 +        ff_fill_rgba_map(rgba_map, inlink->format);
 +        for (i = 0; i < 4; i++)
 +            e->map[i] = rgba_map[e->map[i]];
 +    }
 +
 +    return 0;
 +}
 +
 +static int config_output(AVFilterLink *outlink)
 +{
 +    AVFilterContext *ctx = outlink->src;
 +    AVFilterLink *inlink = ctx->inputs[0];
 +    ExtractPlanesContext *e = ctx->priv;
 +    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
 +    const int output = outlink->srcpad - ctx->output_pads;
 +
 +    if (e->map[output] == 1 || e->map[output] == 2) {
 +        outlink->h = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
 +        outlink->w = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
 +    }
 +
 +    return 0;
 +}
 +
 +static void extract_from_packed(uint8_t *dst, int dst_linesize,
 +                                const uint8_t *src, int src_linesize,
 +                                int width, int height,
 +                                int depth, int step, int comp)
 +{
 +    int x, y;
 +
 +    for (y = 0; y < height; y++) {
 +        switch (depth) {
 +        case 1:
 +            for (x = 0; x < width; x++)
 +                dst[x] = src[x * step + comp];
 +            break;
 +        case 2:
 +            for (x = 0; x < width; x++) {
 +                dst[x * 2    ] = src[x * step + comp * 2    ];
 +                dst[x * 2 + 1] = src[x * step + comp * 2 + 1];
 +            }
 +            break;
 +        }
 +        dst += dst_linesize;
 +        src += src_linesize;
 +    }
 +}
 +
 +static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
 +{
 +    AVFilterContext *ctx = inlink->dst;
 +    ExtractPlanesContext *e = ctx->priv;
 +    int i, eof = 0, ret = 0;
 +
 +    for (i = 0; i < ctx->nb_outputs; i++) {
 +        AVFilterLink *outlink = ctx->outputs[i];
 +        const int idx = e->map[i];
 +        AVFrame *out;
 +
 +        if (outlink->closed)
 +            continue;
 +
 +        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
 +        if (!out) {
 +            ret = AVERROR(ENOMEM);
 +            break;
 +        }
 +        av_frame_copy_props(out, frame);
 +
 +        if (e->is_packed_rgb) {
 +            extract_from_packed(out->data[0], out->linesize[0],
 +                                frame->data[0], frame->linesize[0],
 +                                outlink->w, outlink->h,
 +                                e->depth,
 +                                e->step, idx);
 +        } else {
 +            av_image_copy_plane(out->data[0], out->linesize[0],
 +                                frame->data[idx], frame->linesize[idx],
 +                                e->linesize[idx], outlink->h);
 +        }
 +
 +        ret = ff_filter_frame(outlink, out);
 +        if (ret == AVERROR_EOF)
 +            eof++;
 +        else if (ret < 0)
 +            break;
 +    }
 +    av_frame_free(&frame);
 +
 +    if (eof == ctx->nb_outputs)
 +        ret = AVERROR_EOF;
 +    else if (ret == AVERROR_EOF)
 +        ret = 0;
 +    return ret;
 +}
 +
 +static int init(AVFilterContext *ctx)
 +{
 +    ExtractPlanesContext *e = ctx->priv;
 +    int planes = (e->requested_planes & 0xf) | (e->requested_planes >> 4);
 +    int i;
 +
 +    for (i = 0; i < 4; i++) {
 +        char *name;
 +        AVFilterPad pad = { 0 };
 +
 +        if (!(planes & (1 << i)))
 +            continue;
 +
 +        name = av_asprintf("out%d", ctx->nb_outputs);
 +        if (!name)
 +            return AVERROR(ENOMEM);
 +        e->map[ctx->nb_outputs] = i;
 +        pad.name = name;
 +        pad.type = AVMEDIA_TYPE_VIDEO;
 +        pad.config_props = config_output;
 +
 +        ff_insert_outpad(ctx, ctx->nb_outputs, &pad);
 +    }
 +
 +    return 0;
 +}
 +
 +static av_cold void uninit(AVFilterContext *ctx)
 +{
 +    int i;
 +
 +    for (i = 0; i < ctx->nb_outputs; i++)
 +        av_freep(&ctx->output_pads[i].name);
 +}
 +
 +static const AVFilterPad extractplanes_inputs[] = {
 +    {
 +        .name         = "default",
 +        .type         = AVMEDIA_TYPE_VIDEO,
 +        .filter_frame = filter_frame,
 +        .config_props = config_input,
 +    },
 +    { NULL }
 +};
 +
 +AVFilter avfilter_vf_extractplanes = {
 +    .name          = "extractplanes",
 +    .description   = NULL_IF_CONFIG_SMALL("Extract planes as grayscale frames."),
 +    .priv_size     = sizeof(ExtractPlanesContext),
 +    .priv_class    = &extractplanes_class,
 +    .init          = init,
 +    .uninit        = uninit,
 +    .query_formats = query_formats,
 +    .inputs        = extractplanes_inputs,
 +    .outputs       = NULL,
 +    .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 +};
 +
 +#if CONFIG_ALPHAEXTRACT_FILTER
 +
 +static int init_alphaextract(AVFilterContext *ctx)
 +{
 +    ExtractPlanesContext *e = ctx->priv;
 +
 +    e->requested_planes = PLANE_A;
 +
 +    return init(ctx);
 +}
 +
 +AVFilter avfilter_vf_alphaextract = {
 +    .name           = "alphaextract",
 +    .description    = NULL_IF_CONFIG_SMALL("Extract an alpha channel as a "
 +                      "grayscale image component."),
 +    .priv_size      = sizeof(ExtractPlanesContext),
 +    .init           = init_alphaextract,
 +    .uninit         = uninit,
 +    .query_formats  = query_formats,
 +    .inputs         = extractplanes_inputs,
 +    .outputs        = NULL,
 +    .flags          = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
 +};
 +#endif  /* CONFIG_ALPHAEXTRACT_FILTER */
Simple merge