diff mbox series

[FFmpeg-devel] avfilter: add colorvd video filter

Message ID 20211113121413.294372-1-onemda@gmail.com
State New
Headers show
Series [FFmpeg-devel] avfilter: add colorvd video filter
Related show

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished

Commit Message

Paul B Mahol Nov. 13, 2021, 12:14 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavfilter/Makefile     |   1 +
 libavfilter/allfilters.c |   1 +
 libavfilter/vf_colorvd.c | 259 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 261 insertions(+)
 create mode 100644 libavfilter/vf_colorvd.c

Comments

James Almer Nov. 13, 2021, 12:22 p.m. UTC | #1
On 11/13/2021 9:14 AM, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>   libavfilter/Makefile     |   1 +
>   libavfilter/allfilters.c |   1 +
>   libavfilter/vf_colorvd.c | 259 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 261 insertions(+)
>   create mode 100644 libavfilter/vf_colorvd.c
> 
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 18e28bcc62..8c5e565ed1 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -215,6 +215,7 @@ OBJS-$(CONFIG_COLORLEVELS_FILTER)            += vf_colorlevels.o
>   OBJS-$(CONFIG_COLORMATRIX_FILTER)            += vf_colormatrix.o
>   OBJS-$(CONFIG_COLORSPACE_FILTER)             += vf_colorspace.o colorspace.o colorspacedsp.o
>   OBJS-$(CONFIG_COLORTEMPERATURE_FILTER)       += vf_colortemperature.o
> +OBJS-$(CONFIG_COLORVD_FILTER)                += vf_colorvd.o
>   OBJS-$(CONFIG_CONVOLUTION_FILTER)            += vf_convolution.o
>   OBJS-$(CONFIG_CONVOLUTION_OPENCL_FILTER)     += vf_convolution_opencl.o opencl.o \
>                                                   opencl/convolution.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index 7ec13a15b2..d7556bc93f 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -204,6 +204,7 @@ extern const AVFilter ff_vf_colorlevels;
>   extern const AVFilter ff_vf_colormatrix;
>   extern const AVFilter ff_vf_colorspace;
>   extern const AVFilter ff_vf_colortemperature;
> +extern const AVFilter ff_vf_colorvd;
>   extern const AVFilter ff_vf_convolution;
>   extern const AVFilter ff_vf_convolution_opencl;
>   extern const AVFilter ff_vf_convolve;
> diff --git a/libavfilter/vf_colorvd.c b/libavfilter/vf_colorvd.c
> new file mode 100644
> index 0000000000..c5cec7b318
> --- /dev/null
> +++ b/libavfilter/vf_colorvd.c
> @@ -0,0 +1,259 @@
> +/*
> + * 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 <float.h>
> +
> +#include "libavutil/opt.h"
> +#include "libavutil/imgutils.h"
> +#include "avfilter.h"
> +#include "formats.h"
> +#include "internal.h"
> +#include "video.h"
> +
> +enum ColorVisualDeficiency {
> +    PROTAN,
> +    DEUTAN,
> +    TRITAN,
> +    NB_DEF
> +};
> +
> +static const float lrgb2lms[3][3] =
> +{
> +    { 0.17886, 0.43997, 0.03597 },
> +    { 0.03380, 0.27515, 0.03621 },
> +    { 0.00031, 0.00192, 0.01528 },
> +};
> +
> +static const float lms2lrgb[3][3] =
> +{
> +    {  8.00533, -12.88195,  11.68065 },
> +    { -0.97821,   5.26945, -10.18300 },
> +    { -0.04017,  -0.39885,  66.48079 },
> +};
> +
> +typedef struct Brettel {
> +    int element;
> +    float projection[2][3];
> +    float separation[3];
> +} Brettel;
> +
> +static Brettel brettel[NB_DEF] =
> +{
> +    [PROTAN] = {
> +        0,
> +        {
> +            { 0.00000, 2.18394, -5.65554 },
> +            { 0.00000, 2.16614, -5.30455 },
> +        },
> +        { 0.00000, 0.01751, -0.34516 }
> +    },
> +    [DEUTAN] = {
> +        1,
> +        {
> +            {  0.46165, 0.00000, 2.44885 },
> +            {  0.45789, 0.00000, 2.58960 },
> +        },
> +        { -0.01751, 0.00000, 0.65480 }
> +    },
> +    [TRITAN] = {
> +        2,
> +        {
> +            { -0.00213,  0.05477, 0.00000 },
> +            { -0.06195,  0.16826, 0.00000 },
> +        },
> +        {  0.34516, -0.65480, 0.00000 }

nit: f suffix on all these constants.

> +    }
> +};
> +
> +typedef struct CVDContext {
> +    const AVClass *class;
> +
> +    int deficiency;
> +    float severity;
> +
> +    int (*do_slice)(AVFilterContext *s, void *arg,
> +                    int jobnr, int nb_jobs);
> +} CVDContext;
> +
> +static float apply_dot3(const float vector[3], const float input[3])
> +{
> +    return vector[0] * input[0] + vector[1] * input[1] + vector[2] * input[2];
> +}
> +
> +static void apply_matrix(const float matrix[3][3], const float input[3], float output[3])
> +{
> +    output[0] = matrix[0][0] * input[0] + matrix[0][1] * input[1] + matrix[0][2] * input[2];
> +    output[1] = matrix[1][0] * input[0] + matrix[1][1] * input[1] + matrix[1][2] * input[2];
> +    output[2] = matrix[2][0] * input[0] + matrix[2][1] * input[1] + matrix[2][2] * input[2];
> +}
> +
> +typedef struct ThreadData {
> +    AVFrame *in, *out;
> +} ThreadData;
> +
> +static int cvd_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
> +{
> +    CVDContext *s = ctx->priv;
> +    ThreadData *td = arg;
> +    AVFrame *in = td->in;
> +    AVFrame *out = td->out;
> +    const int width = in->width;
> +    const int height = in->height;
> +    const int slice_start = (height * jobnr) / nb_jobs;
> +    const int slice_end = (height * (jobnr + 1)) / nb_jobs;
> +    const int srlinesize = in->linesize[2] / 4;
> +    const int sglinesize = in->linesize[0] / 4;
> +    const int sblinesize = in->linesize[1] / 4;
> +    const int drlinesize = out->linesize[2] / 4;
> +    const int dglinesize = out->linesize[0] / 4;
> +    const int dblinesize = out->linesize[1] / 4;
> +    const float *sr = (const float *)in->data[2] + slice_start * srlinesize;
> +    const float *sg = (const float *)in->data[0] + slice_start * sglinesize;
> +    const float *sb = (const float *)in->data[1] + slice_start * sblinesize;
> +    float *dr = (float *)out->data[2] + slice_start * drlinesize;
> +    float *dg = (float *)out->data[0] + slice_start * dglinesize;
> +    float *db = (float *)out->data[1] + slice_start * dblinesize;
> +    const float severity = s->severity;
> +    const float iseverity = 1.f - s->severity;
> +    Brettel *cvd = &brettel[s->deficiency];
> +    const int element = cvd->element;
> +
> +    for (int y = slice_start; y < slice_end; y++) {
> +        for (int x = 0; x < width; x++) {
> +            float srgb[3], lms[3];
> +            float *vector;
> +            float projection;
> +            float dot3;
> +
> +            srgb[0] = sr[x];
> +            srgb[1] = sg[x];
> +            srgb[2] = sb[x];
> +
> +            apply_matrix(lrgb2lms, srgb, lms);
> +
> +            dot3 = apply_dot3(cvd->separation, lms);
> +            vector = cvd->projection[dot3 > 0.f];
> +            projection = apply_dot3(vector, lms);
> +            lms[element] = projection * severity + lms[element] * iseverity;
> +
> +            apply_matrix(lms2lrgb, lms, srgb);
> +
> +            dr[x] = srgb[0];
> +            dg[x] = srgb[1];
> +            db[x] = srgb[2];
> +        }
> +
> +        sr += srlinesize;
> +        sg += sglinesize;
> +        sb += sblinesize;
> +        dr += drlinesize;
> +        dg += dglinesize;
> +        db += dblinesize;
> +    }
> +
> +    return 0;
> +}
> +
> +static int filter_frame(AVFilterLink *inlink, AVFrame *in)
> +{
> +    AVFilterContext *ctx = inlink->dst;
> +    AVFilterLink *outlink = ctx->outputs[0];
> +    CVDContext *s = ctx->priv;
> +    ThreadData td;
> +    AVFrame *out;
> +
> +    if (in->color_trc != AVCOL_TRC_LINEAR)
> +        av_log(s, AV_LOG_WARNING, "Color Visual Deficiency filter works correctly only in linear light.\n");
> +
> +    if (av_frame_is_writable(in)) {
> +        out = in;
> +    } else {
> +        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
> +        if (!out) {
> +            av_frame_free(&in);
> +            return AVERROR(ENOMEM);
> +        }
> +        av_frame_copy_props(out, in);
> +    }
> +
> +    td.in = in;
> +    td.out = out;
> +    ff_filter_execute(ctx, s->do_slice, &td, NULL,
> +                      FFMIN(in->height, ff_filter_get_nb_threads(ctx)));
> +
> +    if (in != out) {
> +        av_image_copy_plane(out->data[3], out->linesize[3],
> +            in->data[3], in->linesize[3], outlink->w * 4, outlink->h);
> +        av_frame_free(&in);
> +    }
> +
> +    return ff_filter_frame(ctx->outputs[0], out);
> +}
> +
> +static av_cold int config_input(AVFilterLink *inlink)
> +{
> +    AVFilterContext *ctx = inlink->dst;
> +    CVDContext *s = ctx->priv;
> +
> +    s->do_slice = cvd_slice;
> +
> +    return 0;
> +}
> +
> +static const AVFilterPad colorvd_inputs[] = {
> +    {
> +        .name           = "default",
> +        .type           = AVMEDIA_TYPE_VIDEO,
> +        .filter_frame   = filter_frame,
> +        .config_props   = config_input,
> +    },
> +};
> +
> +static const AVFilterPad colorvd_outputs[] = {
> +    {
> +        .name = "default",
> +        .type = AVMEDIA_TYPE_VIDEO,
> +    },
> +};
> +
> +#define OFFSET(x) offsetof(CVDContext, x)
> +#define VF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
> +#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, VF, unit }
> +
> +static const AVOption colorvd_options[] = {
> +    { "deficiency", "set the type of deficiency", OFFSET(deficiency), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_DEF-1, VF, "def" },
> +    CONST("protan", "", 0, "def"),
> +    CONST("deutan", "", 1, "def"),
> +    CONST("tritan", "", 2, "def"),
> +    { "severity", "set the severity of deficiency", OFFSET(severity), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, VF },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(colorvd);
> +
> +const AVFilter ff_vf_colorvd = {
> +    .name          = "colorvd",
> +    .description   = NULL_IF_CONFIG_SMALL("Simulate Color Visual Deficiencies in the video stream."),

Then maybe call the filter something more identifiable, like 
colordeficiency.

Also, missing docs.

> +    .priv_size     = sizeof(CVDContext),
> +    .priv_class    = &colorvd_class,
> +    FILTER_INPUTS(colorvd_inputs),
> +    FILTER_OUTPUTS(colorvd_outputs),
> +    FILTER_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32),
> +    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
> +    .process_command = ff_filter_process_command,
> +};
>
Anton Khirnov Nov. 19, 2021, 1:18 p.m. UTC | #2
Quoting James Almer (2021-11-13 13:22:12)
> Also, missing docs.

Could we add a development rule that all new filters need docs and all
new filters/codecs/(de)muxers need a test (unless special circumstances,
like hwaccel)?
Michael Niedermayer Nov. 19, 2021, 1:27 p.m. UTC | #3
On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> Quoting James Almer (2021-11-13 13:22:12)
> > Also, missing docs.
> 
> Could we add a development rule that all new filters need docs and all
> new filters/codecs/(de)muxers need a test (unless special circumstances,
> like hwaccel)?

Iam in favor of this

thx

[...]
Paul B Mahol Nov. 19, 2021, 1:55 p.m. UTC | #4
On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <michael@niedermayer.cc>
wrote:

> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> > Quoting James Almer (2021-11-13 13:22:12)
> > > Also, missing docs.
> >
> > Could we add a development rule that all new filters need docs and all
> > new filters/codecs/(de)muxers need a test (unless special circumstances,
> > like hwaccel)?
>
> Iam in favor of this
>
>
Against this, as experimental filters does not need docs, and filters using
floats too.



thx
>
> [...]
>
> --
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> Everything should be made as simple as possible, but not simpler.
> -- Albert Einstein
> _______________________________________________
> 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".
>
Gyan Doshi Nov. 19, 2021, 1:59 p.m. UTC | #5
On 2021-11-19 07:25 pm, Paul B Mahol wrote:
> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <michael@niedermayer.cc>
> wrote:
>
>> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
>>> Quoting James Almer (2021-11-13 13:22:12)
>>>> Also, missing docs.
>>> Could we add a development rule that all new filters need docs and all
>>> new filters/codecs/(de)muxers need a test (unless special circumstances,
>>> like hwaccel)?
>> Iam in favor of this
>>
>>
> Against this, as experimental filters does not need docs, and filters using
> floats too.\

If it's available for regular users to use,  it needs docs.

Regards,
Gyan
Paul B Mahol Nov. 19, 2021, 2:04 p.m. UTC | #6
On Fri, Nov 19, 2021 at 3:00 PM Gyan Doshi <ffmpeg@gyani.pro> wrote:

>
>
> On 2021-11-19 07:25 pm, Paul B Mahol wrote:
> > On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
> michael@niedermayer.cc>
> > wrote:
> >
> >> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> >>> Quoting James Almer (2021-11-13 13:22:12)
> >>>> Also, missing docs.
> >>> Could we add a development rule that all new filters need docs and all
> >>> new filters/codecs/(de)muxers need a test (unless special
> circumstances,
> >>> like hwaccel)?
> >> Iam in favor of this
> >>
> >>
> > Against this, as experimental filters does not need docs, and filters
> using
> > floats too.\
>
> If it's available for regular users to use,  it needs docs.
>

Do you see anywhere this filter available for users?


>
> Regards,
> Gyan
> _______________________________________________
> 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".
>
Anton Khirnov Nov. 19, 2021, 2:04 p.m. UTC | #7
Quoting Paul B Mahol (2021-11-19 14:55:42)
> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <michael@niedermayer.cc>
> wrote:
> 
> > On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> > > Quoting James Almer (2021-11-13 13:22:12)
> > > > Also, missing docs.
> > >
> > > Could we add a development rule that all new filters need docs and all
> > > new filters/codecs/(de)muxers need a test (unless special circumstances,
> > > like hwaccel)?
> >
> > Iam in favor of this
> >
> >
> Against this, as experimental filters does not need docs,

I strongly disagree, even experimental code needs docs. I often find it
good idea to write documentation _before_ writing the code.

Besides, experimental filters do not belong in the main repository. Keep
them in your tree until stop being experimental.

> floats too.

This is an excuse, we have ways of dealing with floats.
Paul B Mahol Nov. 19, 2021, 2:07 p.m. UTC | #8
On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:

> Quoting Paul B Mahol (2021-11-19 14:55:42)
> > On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
> michael@niedermayer.cc>
> > wrote:
> >
> > > On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> > > > Quoting James Almer (2021-11-13 13:22:12)
> > > > > Also, missing docs.
> > > >
> > > > Could we add a development rule that all new filters need docs and
> all
> > > > new filters/codecs/(de)muxers need a test (unless special
> circumstances,
> > > > like hwaccel)?
> > >
> > > Iam in favor of this
> > >
> > >
> > Against this, as experimental filters does not need docs,
>
> I strongly disagree, even experimental code needs docs. I often find it
> good idea to write documentation _before_ writing the code.
>
> Besides, experimental filters do not belong in the main repository. Keep
> them in your tree until stop being experimental.
>


Never, I will keep posting filters without docs on devel mailing list as I
wish.


>
> > floats too.
>
> This is an excuse, we have ways of dealing with floats.
>

Citations needed.


>
> --
> Anton Khirnov
>
Anton Khirnov Nov. 19, 2021, 2:25 p.m. UTC | #9
Quoting Paul B Mahol (2021-11-19 15:07:13)
> On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:
> 
> > Quoting Paul B Mahol (2021-11-19 14:55:42)
> > > On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
> > michael@niedermayer.cc>
> > > wrote:
> > >
> > > > On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> > > > > Quoting James Almer (2021-11-13 13:22:12)
> > > > > > Also, missing docs.
> > > > >
> > > > > Could we add a development rule that all new filters need docs and
> > all
> > > > > new filters/codecs/(de)muxers need a test (unless special
> > circumstances,
> > > > > like hwaccel)?
> > > >
> > > > Iam in favor of this
> > > >
> > > >
> > > Against this, as experimental filters does not need docs,
> >
> > I strongly disagree, even experimental code needs docs. I often find it
> > good idea to write documentation _before_ writing the code.
> >
> > Besides, experimental filters do not belong in the main repository. Keep
> > them in your tree until stop being experimental.
> >
> 
> 
> Never, I will keep posting filters without docs on devel mailing list as I
> wish.

Any such patches are rejected.

I really wish you stopped with these kinds of tantrums, they accomplish
nothing useful, waste everyone's time and make the project look bad.


> 
> 
> >
> > > floats too.
> >
> > This is an excuse, we have ways of dealing with floats.
> >
> 
> Citations needed.

tests/tiny_psnr.c for example. As I'm sure you know very well.
James Almer Nov. 19, 2021, 2:29 p.m. UTC | #10
On 11/19/2021 11:07 AM, Paul B Mahol wrote:
> On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:
> 
>> Quoting Paul B Mahol (2021-11-19 14:55:42)
>>> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
>> michael@niedermayer.cc>
>>> wrote:
>>>
>>>> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
>>>>> Quoting James Almer (2021-11-13 13:22:12)
>>>>>> Also, missing docs.
>>>>>
>>>>> Could we add a development rule that all new filters need docs and
>> all
>>>>> new filters/codecs/(de)muxers need a test (unless special
>> circumstances,
>>>>> like hwaccel)?
>>>>
>>>> Iam in favor of this
>>>>
>>>>
>>> Against this, as experimental filters does not need docs,
>>
>> I strongly disagree, even experimental code needs docs. I often find it
>> good idea to write documentation _before_ writing the code.
>>
>> Besides, experimental filters do not belong in the main repository. Keep
>> them in your tree until stop being experimental.
>>
> 
> 
> Never, I will keep posting filters without docs on devel mailing list as I
> wish.

Even if you joke, nobody finds it funny, and it's annoying. So really, 
stop already.

> 
> 
>>
>>> floats too.
>>
>> This is an excuse, we have ways of dealing with floats.
>>
> 
> Citations needed.
> 
> 
>>
>> --
>> Anton Khirnov
>>
> _______________________________________________
> 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".
>
Paul B Mahol Nov. 19, 2021, 2:34 p.m. UTC | #11
On Fri, Nov 19, 2021 at 3:25 PM Anton Khirnov <anton@khirnov.net> wrote:

> Quoting Paul B Mahol (2021-11-19 15:07:13)
> > On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:
> >
> > > Quoting Paul B Mahol (2021-11-19 14:55:42)
> > > > On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
> > > michael@niedermayer.cc>
> > > > wrote:
> > > >
> > > > > On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> > > > > > Quoting James Almer (2021-11-13 13:22:12)
> > > > > > > Also, missing docs.
> > > > > >
> > > > > > Could we add a development rule that all new filters need docs
> and
> > > all
> > > > > > new filters/codecs/(de)muxers need a test (unless special
> > > circumstances,
> > > > > > like hwaccel)?
> > > > >
> > > > > Iam in favor of this
> > > > >
> > > > >
> > > > Against this, as experimental filters does not need docs,
> > >
> > > I strongly disagree, even experimental code needs docs. I often find it
> > > good idea to write documentation _before_ writing the code.
> > >
> > > Besides, experimental filters do not belong in the main repository.
> Keep
> > > them in your tree until stop being experimental.
> > >
> >
> >
> > Never, I will keep posting filters without docs on devel mailing list as
> I
> > wish.
>
> Any such patches are rejected.
>

I post patches to get constructive reviews and feedback, but sometimes
I receive only hate and bait to fight back.


>
> I really wish you stopped with these kinds of tantrums, they accomplish
> nothing useful, waste everyone's time and make the project look bad.
>

Please keep this aggressive ad-hominem behavior for yourself.

>
>
> >
> >
> > >
> > > > floats too.
> > >
> > > This is an excuse, we have ways of dealing with floats.
> > >
> >
> > Citations needed.
>
> tests/tiny_psnr.c for example. As I'm sure you know very well.
>

Cite single video filter test using that.


>
> --
> Anton Khirnov
>
James Almer Nov. 19, 2021, 2:37 p.m. UTC | #12
On 11/19/2021 11:34 AM, Paul B Mahol wrote:
> On Fri, Nov 19, 2021 at 3:25 PM Anton Khirnov <anton@khirnov.net> wrote:
> 
>> Quoting Paul B Mahol (2021-11-19 15:07:13)
>>> On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:
>>>
>>>> Quoting Paul B Mahol (2021-11-19 14:55:42)
>>>>> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
>>>> michael@niedermayer.cc>
>>>>> wrote:
>>>>>
>>>>>> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
>>>>>>> Quoting James Almer (2021-11-13 13:22:12)
>>>>>>>> Also, missing docs.
>>>>>>>
>>>>>>> Could we add a development rule that all new filters need docs
>> and
>>>> all
>>>>>>> new filters/codecs/(de)muxers need a test (unless special
>>>> circumstances,
>>>>>>> like hwaccel)?
>>>>>>
>>>>>> Iam in favor of this
>>>>>>
>>>>>>
>>>>> Against this, as experimental filters does not need docs,
>>>>
>>>> I strongly disagree, even experimental code needs docs. I often find it
>>>> good idea to write documentation _before_ writing the code.
>>>>
>>>> Besides, experimental filters do not belong in the main repository.
>> Keep
>>>> them in your tree until stop being experimental.
>>>>
>>>
>>>
>>> Never, I will keep posting filters without docs on devel mailing list as
>> I
>>> wish.
>>
>> Any such patches are rejected.
>>
> 
> I post patches to get constructive reviews and feedback, but sometimes
> I receive only hate and bait to fight back.

You got a review with some feedback from myself for this patch. How it 
ended up with you reacting like this after i asked you to document the 
filter beats me.
Paul B Mahol Nov. 19, 2021, 2:38 p.m. UTC | #13
On Fri, Nov 19, 2021 at 3:29 PM James Almer <jamrial@gmail.com> wrote:

> On 11/19/2021 11:07 AM, Paul B Mahol wrote:
> > On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:
> >
> >> Quoting Paul B Mahol (2021-11-19 14:55:42)
> >>> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
> >> michael@niedermayer.cc>
> >>> wrote:
> >>>
> >>>> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> >>>>> Quoting James Almer (2021-11-13 13:22:12)
> >>>>>> Also, missing docs.
> >>>>>
> >>>>> Could we add a development rule that all new filters need docs and
> >> all
> >>>>> new filters/codecs/(de)muxers need a test (unless special
> >> circumstances,
> >>>>> like hwaccel)?
> >>>>
> >>>> Iam in favor of this
> >>>>
> >>>>
> >>> Against this, as experimental filters does not need docs,
> >>
> >> I strongly disagree, even experimental code needs docs. I often find it
> >> good idea to write documentation _before_ writing the code.
> >>
> >> Besides, experimental filters do not belong in the main repository. Keep
> >> them in your tree until stop being experimental.
> >>
> >
> >
> > Never, I will keep posting filters without docs on devel mailing list as
> I
> > wish.
>
> Even if you joke, nobody finds it funny, and it's annoying. So really,
> stop already.
>

Not joking, as explained to uneducated, sending patches without docs first
time is OK.
This is for testing ground approach. Off course not gonna push filter to
git master without some kind of docs.


>
> >
> >
> >>
> >>> floats too.
> >>
> >> This is an excuse, we have ways of dealing with floats.
> >>
> >
> > Citations needed.
> >
> >
> >>
> >> --
> >> Anton Khirnov
> >>
> > _______________________________________________
> > 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".
>
James Almer Nov. 19, 2021, 2:41 p.m. UTC | #14
On 11/19/2021 11:38 AM, Paul B Mahol wrote:
> On Fri, Nov 19, 2021 at 3:29 PM James Almer <jamrial@gmail.com> wrote:
> 
>> On 11/19/2021 11:07 AM, Paul B Mahol wrote:
>>> On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net> wrote:
>>>
>>>> Quoting Paul B Mahol (2021-11-19 14:55:42)
>>>>> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
>>>> michael@niedermayer.cc>
>>>>> wrote:
>>>>>
>>>>>> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
>>>>>>> Quoting James Almer (2021-11-13 13:22:12)
>>>>>>>> Also, missing docs.
>>>>>>>
>>>>>>> Could we add a development rule that all new filters need docs and
>>>> all
>>>>>>> new filters/codecs/(de)muxers need a test (unless special
>>>> circumstances,
>>>>>>> like hwaccel)?
>>>>>>
>>>>>> Iam in favor of this
>>>>>>
>>>>>>
>>>>> Against this, as experimental filters does not need docs,
>>>>
>>>> I strongly disagree, even experimental code needs docs. I often find it
>>>> good idea to write documentation _before_ writing the code.
>>>>
>>>> Besides, experimental filters do not belong in the main repository. Keep
>>>> them in your tree until stop being experimental.
>>>>
>>>
>>>
>>> Never, I will keep posting filters without docs on devel mailing list as
>> I
>>> wish.
>>
>> Even if you joke, nobody finds it funny, and it's annoying. So really,
>> stop already.
>>
> 
> Not joking, as explained to uneducated, sending patches without docs first
> time is OK.
> This is for testing ground approach. Off course not gonna push filter to
> git master without some kind of docs.

Ok, that's completely fine. But then why didn't you just said that the 
first time instead? Just saying "Will not write docs for the first 
draft, will do it for the final version" or similar would have prevented 
this entire thread.

> 
> 
>>
>>>
>>>
>>>>
>>>>> floats too.
>>>>
>>>> This is an excuse, we have ways of dealing with floats.
>>>>
>>>
>>> Citations needed.
>>>
>>>
>>>>
>>>> --
>>>> Anton Khirnov
>>>>
>>> _______________________________________________
>>> 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".
>
Paul B Mahol Nov. 19, 2021, 2:41 p.m. UTC | #15
On Fri, Nov 19, 2021 at 3:37 PM James Almer <jamrial@gmail.com> wrote:

> On 11/19/2021 11:34 AM, Paul B Mahol wrote:
> > On Fri, Nov 19, 2021 at 3:25 PM Anton Khirnov <anton@khirnov.net> wrote:
> >
> >> Quoting Paul B Mahol (2021-11-19 15:07:13)
> >>> On Fri, Nov 19, 2021 at 3:04 PM Anton Khirnov <anton@khirnov.net>
> wrote:
> >>>
> >>>> Quoting Paul B Mahol (2021-11-19 14:55:42)
> >>>>> On Fri, Nov 19, 2021 at 2:27 PM Michael Niedermayer <
> >>>> michael@niedermayer.cc>
> >>>>> wrote:
> >>>>>
> >>>>>> On Fri, Nov 19, 2021 at 02:18:27PM +0100, Anton Khirnov wrote:
> >>>>>>> Quoting James Almer (2021-11-13 13:22:12)
> >>>>>>>> Also, missing docs.
> >>>>>>>
> >>>>>>> Could we add a development rule that all new filters need docs
> >> and
> >>>> all
> >>>>>>> new filters/codecs/(de)muxers need a test (unless special
> >>>> circumstances,
> >>>>>>> like hwaccel)?
> >>>>>>
> >>>>>> Iam in favor of this
> >>>>>>
> >>>>>>
> >>>>> Against this, as experimental filters does not need docs,
> >>>>
> >>>> I strongly disagree, even experimental code needs docs. I often find
> it
> >>>> good idea to write documentation _before_ writing the code.
> >>>>
> >>>> Besides, experimental filters do not belong in the main repository.
> >> Keep
> >>>> them in your tree until stop being experimental.
> >>>>
> >>>
> >>>
> >>> Never, I will keep posting filters without docs on devel mailing list
> as
> >> I
> >>> wish.
> >>
> >> Any such patches are rejected.
> >>
> >
> > I post patches to get constructive reviews and feedback, but sometimes
> > I receive only hate and bait to fight back.
>
> You got a review with some feedback from myself for this patch. How it
> ended up with you reacting like this after i asked you to document the
> filter beats me.
>

Your review is OK. I wanted to write docs and rename filter after some time
passed
and than send new patch to list.


> _______________________________________________
> 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/Makefile b/libavfilter/Makefile
index 18e28bcc62..8c5e565ed1 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -215,6 +215,7 @@  OBJS-$(CONFIG_COLORLEVELS_FILTER)            += vf_colorlevels.o
 OBJS-$(CONFIG_COLORMATRIX_FILTER)            += vf_colormatrix.o
 OBJS-$(CONFIG_COLORSPACE_FILTER)             += vf_colorspace.o colorspace.o colorspacedsp.o
 OBJS-$(CONFIG_COLORTEMPERATURE_FILTER)       += vf_colortemperature.o
+OBJS-$(CONFIG_COLORVD_FILTER)                += vf_colorvd.o
 OBJS-$(CONFIG_CONVOLUTION_FILTER)            += vf_convolution.o
 OBJS-$(CONFIG_CONVOLUTION_OPENCL_FILTER)     += vf_convolution_opencl.o opencl.o \
                                                 opencl/convolution.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 7ec13a15b2..d7556bc93f 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -204,6 +204,7 @@  extern const AVFilter ff_vf_colorlevels;
 extern const AVFilter ff_vf_colormatrix;
 extern const AVFilter ff_vf_colorspace;
 extern const AVFilter ff_vf_colortemperature;
+extern const AVFilter ff_vf_colorvd;
 extern const AVFilter ff_vf_convolution;
 extern const AVFilter ff_vf_convolution_opencl;
 extern const AVFilter ff_vf_convolve;
diff --git a/libavfilter/vf_colorvd.c b/libavfilter/vf_colorvd.c
new file mode 100644
index 0000000000..c5cec7b318
--- /dev/null
+++ b/libavfilter/vf_colorvd.c
@@ -0,0 +1,259 @@ 
+/*
+ * 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 <float.h>
+
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum ColorVisualDeficiency {
+    PROTAN,
+    DEUTAN,
+    TRITAN,
+    NB_DEF
+};
+
+static const float lrgb2lms[3][3] =
+{
+    { 0.17886, 0.43997, 0.03597 },
+    { 0.03380, 0.27515, 0.03621 },
+    { 0.00031, 0.00192, 0.01528 },
+};
+
+static const float lms2lrgb[3][3] =
+{
+    {  8.00533, -12.88195,  11.68065 },
+    { -0.97821,   5.26945, -10.18300 },
+    { -0.04017,  -0.39885,  66.48079 },
+};
+
+typedef struct Brettel {
+    int element;
+    float projection[2][3];
+    float separation[3];
+} Brettel;
+
+static Brettel brettel[NB_DEF] =
+{
+    [PROTAN] = {
+        0,
+        {
+            { 0.00000, 2.18394, -5.65554 },
+            { 0.00000, 2.16614, -5.30455 },
+        },
+        { 0.00000, 0.01751, -0.34516 }
+    },
+    [DEUTAN] = {
+        1,
+        {
+            {  0.46165, 0.00000, 2.44885 },
+            {  0.45789, 0.00000, 2.58960 },
+        },
+        { -0.01751, 0.00000, 0.65480 }
+    },
+    [TRITAN] = {
+        2,
+        {
+            { -0.00213,  0.05477, 0.00000 },
+            { -0.06195,  0.16826, 0.00000 },
+        },
+        {  0.34516, -0.65480, 0.00000 }
+    }
+};
+
+typedef struct CVDContext {
+    const AVClass *class;
+
+    int deficiency;
+    float severity;
+
+    int (*do_slice)(AVFilterContext *s, void *arg,
+                    int jobnr, int nb_jobs);
+} CVDContext;
+
+static float apply_dot3(const float vector[3], const float input[3])
+{
+    return vector[0] * input[0] + vector[1] * input[1] + vector[2] * input[2];
+}
+
+static void apply_matrix(const float matrix[3][3], const float input[3], float output[3])
+{
+    output[0] = matrix[0][0] * input[0] + matrix[0][1] * input[1] + matrix[0][2] * input[2];
+    output[1] = matrix[1][0] * input[0] + matrix[1][1] * input[1] + matrix[1][2] * input[2];
+    output[2] = matrix[2][0] * input[0] + matrix[2][1] * input[1] + matrix[2][2] * input[2];
+}
+
+typedef struct ThreadData {
+    AVFrame *in, *out;
+} ThreadData;
+
+static int cvd_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+    CVDContext *s = ctx->priv;
+    ThreadData *td = arg;
+    AVFrame *in = td->in;
+    AVFrame *out = td->out;
+    const int width = in->width;
+    const int height = in->height;
+    const int slice_start = (height * jobnr) / nb_jobs;
+    const int slice_end = (height * (jobnr + 1)) / nb_jobs;
+    const int srlinesize = in->linesize[2] / 4;
+    const int sglinesize = in->linesize[0] / 4;
+    const int sblinesize = in->linesize[1] / 4;
+    const int drlinesize = out->linesize[2] / 4;
+    const int dglinesize = out->linesize[0] / 4;
+    const int dblinesize = out->linesize[1] / 4;
+    const float *sr = (const float *)in->data[2] + slice_start * srlinesize;
+    const float *sg = (const float *)in->data[0] + slice_start * sglinesize;
+    const float *sb = (const float *)in->data[1] + slice_start * sblinesize;
+    float *dr = (float *)out->data[2] + slice_start * drlinesize;
+    float *dg = (float *)out->data[0] + slice_start * dglinesize;
+    float *db = (float *)out->data[1] + slice_start * dblinesize;
+    const float severity = s->severity;
+    const float iseverity = 1.f - s->severity;
+    Brettel *cvd = &brettel[s->deficiency];
+    const int element = cvd->element;
+
+    for (int y = slice_start; y < slice_end; y++) {
+        for (int x = 0; x < width; x++) {
+            float srgb[3], lms[3];
+            float *vector;
+            float projection;
+            float dot3;
+
+            srgb[0] = sr[x];
+            srgb[1] = sg[x];
+            srgb[2] = sb[x];
+
+            apply_matrix(lrgb2lms, srgb, lms);
+
+            dot3 = apply_dot3(cvd->separation, lms);
+            vector = cvd->projection[dot3 > 0.f];
+            projection = apply_dot3(vector, lms);
+            lms[element] = projection * severity + lms[element] * iseverity;
+
+            apply_matrix(lms2lrgb, lms, srgb);
+
+            dr[x] = srgb[0];
+            dg[x] = srgb[1];
+            db[x] = srgb[2];
+        }
+
+        sr += srlinesize;
+        sg += sglinesize;
+        sb += sblinesize;
+        dr += drlinesize;
+        dg += dglinesize;
+        db += dblinesize;
+    }
+
+    return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterContext *ctx = inlink->dst;
+    AVFilterLink *outlink = ctx->outputs[0];
+    CVDContext *s = ctx->priv;
+    ThreadData td;
+    AVFrame *out;
+
+    if (in->color_trc != AVCOL_TRC_LINEAR)
+        av_log(s, AV_LOG_WARNING, "Color Visual Deficiency filter works correctly only in linear light.\n");
+
+    if (av_frame_is_writable(in)) {
+        out = in;
+    } else {
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+        if (!out) {
+            av_frame_free(&in);
+            return AVERROR(ENOMEM);
+        }
+        av_frame_copy_props(out, in);
+    }
+
+    td.in = in;
+    td.out = out;
+    ff_filter_execute(ctx, s->do_slice, &td, NULL,
+                      FFMIN(in->height, ff_filter_get_nb_threads(ctx)));
+
+    if (in != out) {
+        av_image_copy_plane(out->data[3], out->linesize[3],
+            in->data[3], in->linesize[3], outlink->w * 4, outlink->h);
+        av_frame_free(&in);
+    }
+
+    return ff_filter_frame(ctx->outputs[0], out);
+}
+
+static av_cold int config_input(AVFilterLink *inlink)
+{
+    AVFilterContext *ctx = inlink->dst;
+    CVDContext *s = ctx->priv;
+
+    s->do_slice = cvd_slice;
+
+    return 0;
+}
+
+static const AVFilterPad colorvd_inputs[] = {
+    {
+        .name           = "default",
+        .type           = AVMEDIA_TYPE_VIDEO,
+        .filter_frame   = filter_frame,
+        .config_props   = config_input,
+    },
+};
+
+static const AVFilterPad colorvd_outputs[] = {
+    {
+        .name = "default",
+        .type = AVMEDIA_TYPE_VIDEO,
+    },
+};
+
+#define OFFSET(x) offsetof(CVDContext, x)
+#define VF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, VF, unit }
+
+static const AVOption colorvd_options[] = {
+    { "deficiency", "set the type of deficiency", OFFSET(deficiency), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_DEF-1, VF, "def" },
+    CONST("protan", "", 0, "def"),
+    CONST("deutan", "", 1, "def"),
+    CONST("tritan", "", 2, "def"),
+    { "severity", "set the severity of deficiency", OFFSET(severity), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, VF },
+    { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(colorvd);
+
+const AVFilter ff_vf_colorvd = {
+    .name          = "colorvd",
+    .description   = NULL_IF_CONFIG_SMALL("Simulate Color Visual Deficiencies in the video stream."),
+    .priv_size     = sizeof(CVDContext),
+    .priv_class    = &colorvd_class,
+    FILTER_INPUTS(colorvd_inputs),
+    FILTER_OUTPUTS(colorvd_outputs),
+    FILTER_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32),
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+    .process_command = ff_filter_process_command,
+};