[FFmpeg-devel] [PATCH] avfilter: add mergeplanes

Paul B Mahol onemda at gmail.com
Mon Sep 30 11:40:07 CEST 2013


On 9/30/13, Nicolas George <george at nsup.org> wrote:
> Le nonidi 9 vendemiaire, an CCXXII, Paul B Mahol a ecrit :
>> Signed-off-by: Paul B Mahol <onemda at gmail.com>
>> ---
>>  doc/filters.texi             |  20 ++++
>>  libavfilter/Makefile         |   1 +
>>  libavfilter/allfilters.c     |   1 +
>>  libavfilter/vf_mergeplanes.c | 227
>> +++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 249 insertions(+)
>>  create mode 100644 libavfilter/vf_mergeplanes.c
>>
>> diff --git a/doc/filters.texi b/doc/filters.texi
>> index bd39495..9d8c7cc 100644
>> --- a/doc/filters.texi
>> +++ b/doc/filters.texi
>> @@ -5248,6 +5248,26 @@ lutyuv=y='bitand(val, 128+64+32)'
>>  @end example
>>  @end itemize
>>
>> + at section mergeplanes
>> +
>> +Merge color channel components from several video streams.
>
> Good idea.
>
>> +
>> +This filter accepts the following options:
>> + at table @option
>> + at item inputs
>> +Set the number of inputs. Default is 2.
>> + at end table
>
> I have concerns about usability: why does 2 mean YUV+A instead of GRAY+A?

Indeed, but there is no planar gray8a, but adding support for packed
merge is not hard at all.

It could be allowed to merge various stuff, but should I handle that
in query_formats?
Or just put supported I/O formats there and add checks in config_output?

> And if 3 means Y+U+V, how do you express R+G+B? Maybe something like that
> would be more appropriate:
>
> 	mode=y_u_v
> 	mode=yuv_a
>
> Or, possibly using additive features:
>
> 	mode=y+u+v
> 	mode=yuv+a
>
> (note that in that case, yuv must be a different value from y+u+v; I
> suppose
> each of y, u, v, yuv, r, g, b, rgb, alpha need its own bit)

So mode explicitly sets what input and output formats filter will
accept?

>
> Support for more formats can come later, of course, but the user interface
> need to be ready to avoid compatibility concerns.

I wonder what is most sane/logical/useful filter syntax/whatever.

>

[...]

>> +    AVFilterContext *ctx = fs->parent;
>> +    AVFilterLink *outlink = ctx->outputs[0];
>> +    MergePlanesContext *s = fs->opaque;
>> +    AVFrame *in[4] = { NULL };
>> +    AVFrame *out;
>> +    int i, ret = 0;
>> +
>> +    av_assert0(s->nb_inputs <= 4);
>> +    for (i = 0; i < s->nb_inputs; i++) {
>
>> +        if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], s->nb_inputs
>> - (i + 1))) < 0)
>
> I wonder about the last argument: "s->nb_inputs - (i + 1)". It looks like
> you are using the input frames read-only, therefore, 0 should be just fine.

Will try.

>
>> +            return ret;
>> +    }
>> +
>> +    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
>> +    if (!out)
>> +        return AVERROR(ENOMEM);
>> +
>
>> +    out->pts = av_rescale_q(in[0]->pts, s->fs.time_base,
>> outlink->time_base);
>
> The correct timestamp is in s->fs.pts; in[0]->pts may be wrong if the same
> frame is duplicated to sync with the other streams.

Thanks. Fixed.

>
>> +    merge_planes(ctx, in, out);
>> +    ret = ff_filter_frame(outlink, out);
>> +
>> +    return ret;
>> +}
>> +
>> +static int config_output(AVFilterLink *outlink)
>> +{
>> +    AVFilterContext *ctx = outlink->src;
>> +    MergePlanesContext *s = ctx->priv;
>> +    FFFrameSyncIn *in = s->fs.in;
>> +    int i, ret;
>> +
>> +    ff_framesync_init(&s->fs, ctx, s->nb_inputs);
>> +    s->fs.opaque = s;
>> +    s->fs.on_event = process_frame;
>> +
>> +    for (i = 0; i < s->nb_inputs; i++) {
>> +        AVFilterLink *inlink = ctx->inputs[i];
>> +        const AVPixFmtDescriptor *desc =
>> av_pix_fmt_desc_get(inlink->format);
>> +
>> +        if ((ret = av_image_fill_linesizes(s->planewidth[i],
>> inlink->format, inlink->w)) < 0)
>> +            return ret;
>> +
>> +        s->planeheight[i][1] =
>> +        s->planeheight[i][2] = FF_CEIL_RSHIFT(inlink->h,
>> desc->log2_chroma_h);
>> +        s->planeheight[i][0] =
>> +        s->planeheight[i][3] = inlink->h;
>> +        s->nb_planes[i] = av_pix_fmt_count_planes(inlink->format);
>
> I do not understand the logic here: unless I am missing something, there
> should be a check that all input streams have compatible sizes (i.e., since
> only 444 is supported, all the same size) (and pixel aspect ratio too).

Yes, I'm just lazy...

>
>> +
>> +        in[i].time_base = inlink->time_base;
>> +        in[i].sync   = 1;
>> +        in[i].before = EXT_STOP;
>> +        in[i].after  = EXT_STOP;
>> +    }
>> +
>> +    return ff_framesync_configure(&s->fs);
>> +}
>> +

[...]


More information about the ffmpeg-devel mailing list