diff mbox series

[FFmpeg-devel] avutil/csp: create public API for colorspace structs

Message ID 20220513154208.17941-1-leo.izen@gmail.com
State New
Headers show
Series [FFmpeg-devel] avutil/csp: create public API for colorspace structs | expand

Checks

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

Commit Message

Leo Izen May 13, 2022, 3:42 p.m. UTC
This commit moves some of the functionality from avfilter/colorspace
into avutil/csp and exposes it as a public API so it can be used by
libavcodec and/or libavformat.
---
 libavfilter/colorspace.c    |  88 ----------------------------
 libavfilter/colorspace.h    |  25 +-------
 libavfilter/fflcms2.c       |   3 +-
 libavfilter/fflcms2.h       |   2 +-
 libavfilter/vf_colorspace.c |   9 +--
 libavfilter/vf_iccdetect.c  |   3 +-
 libavutil/Makefile          |   2 +
 libavutil/csp.c             | 111 ++++++++++++++++++++++++++++++++++++
 libavutil/csp.h             |  49 ++++++++++++++++
 9 files changed, 173 insertions(+), 119 deletions(-)
 create mode 100644 libavutil/csp.c
 create mode 100644 libavutil/csp.h

Comments

Ronald S. Bultje May 13, 2022, 7:14 p.m. UTC | #1
Hi,

On Fri, May 13, 2022 at 11:42 AM Leo Izen <leo.izen@gmail.com> wrote:

> This commit moves some of the functionality from avfilter/colorspace
> into avutil/csp and exposes it as a public API so it can be used by
> libavcodec and/or libavformat.
> ---
>  libavfilter/colorspace.c    |  88 ----------------------------
>  libavfilter/colorspace.h    |  25 +-------
>  libavfilter/fflcms2.c       |   3 +-
>  libavfilter/fflcms2.h       |   2 +-
>  libavfilter/vf_colorspace.c |   9 +--
>  libavfilter/vf_iccdetect.c  |   3 +-
>  libavutil/Makefile          |   2 +
>  libavutil/csp.c             | 111 ++++++++++++++++++++++++++++++++++++
>  libavutil/csp.h             |  49 ++++++++++++++++
>  9 files changed, 173 insertions(+), 119 deletions(-)
>  create mode 100644 libavutil/csp.c
>  create mode 100644 libavutil/csp.h
>

I don't have objections.

Ronald
James Almer May 13, 2022, 7:18 p.m. UTC | #2
On 5/13/2022 12:42 PM, Leo Izen wrote:
> This commit moves some of the functionality from avfilter/colorspace
> into avutil/csp and exposes it as a public API so it can be used by
> libavcodec and/or libavformat.

If it's of no use for library users, then make them avpriv_ and not 
installed.

> ---
>   libavfilter/colorspace.c    |  88 ----------------------------
>   libavfilter/colorspace.h    |  25 +-------
>   libavfilter/fflcms2.c       |   3 +-
>   libavfilter/fflcms2.h       |   2 +-
>   libavfilter/vf_colorspace.c |   9 +--
>   libavfilter/vf_iccdetect.c  |   3 +-
>   libavutil/Makefile          |   2 +
>   libavutil/csp.c             | 111 ++++++++++++++++++++++++++++++++++++
>   libavutil/csp.h             |  49 ++++++++++++++++
>   9 files changed, 173 insertions(+), 119 deletions(-)
>   create mode 100644 libavutil/csp.c
>   create mode 100644 libavutil/csp.h
> 
> diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
> index 8d7b882375..f22e7002e1 100644
> --- a/libavfilter/colorspace.c
> +++ b/libavfilter/colorspace.c
> @@ -107,94 +107,6 @@ static const double gbr_matrix[3][3] =
>       { 0.5, -0.5, 0   },
>   };
>   
> -/*
> - * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html
> - * The older ones (bt470bg/m) are also explained in their respective ITU docs
> - * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf)
> - * whereas the newer ones can typically be copied directly from wikipedia :)
> - */
> -static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
> -    [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
> -    [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
> -    [AVCOL_SPC_SMPTE170M]  = { 0.299,  0.587,  0.114  },
> -    [AVCOL_SPC_BT709]      = { 0.2126, 0.7152, 0.0722 },
> -    [AVCOL_SPC_SMPTE240M]  = { 0.212,  0.701,  0.087  },
> -    [AVCOL_SPC_YCOCG]      = { 0.25,   0.5,    0.25   },
> -    [AVCOL_SPC_RGB]        = { 1,      1,      1      },
> -    [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 },
> -    [AVCOL_SPC_BT2020_CL]  = { 0.2627, 0.6780, 0.0593 },
> -};
> -
> -const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp)
> -{
> -    const struct LumaCoefficients *coeffs;
> -
> -    if (csp >= AVCOL_SPC_NB)
> -        return NULL;
> -    coeffs = &luma_coefficients[csp];
> -    if (!coeffs->cr)
> -        return NULL;
> -
> -    return coeffs;
> -}
> -
> -#define WP_D65 { 0.3127, 0.3290 }
> -#define WP_C   { 0.3100, 0.3160 }
> -#define WP_DCI { 0.3140, 0.3510 }
> -#define WP_E   { 1/3.0f, 1/3.0f }
> -
> -static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = {
> -    [AVCOL_PRI_BT709]     = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } },
> -    [AVCOL_PRI_BT470M]    = { WP_C,   { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } },
> -    [AVCOL_PRI_BT470BG]   = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } },
> -    [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> -    [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> -    [AVCOL_PRI_SMPTE428]  = { WP_E,   { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } },
> -    [AVCOL_PRI_SMPTE431]  = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> -    [AVCOL_PRI_SMPTE432]  = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> -    [AVCOL_PRI_FILM]      = { WP_C,   { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } },
> -    [AVCOL_PRI_BT2020]    = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } },
> -    [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } },
> -};
> -
> -const struct ColorPrimaries *ff_get_color_primaries(enum AVColorPrimaries prm)
> -{
> -    const struct ColorPrimaries *p;
> -
> -    if (prm >= AVCOL_PRI_NB)
> -        return NULL;
> -    p = &color_primaries[prm];
> -    if (!p->prim.xr)
> -        return NULL;
> -
> -    return p;
> -}
> -
> -enum AVColorPrimaries ff_detect_color_primaries(const struct ColorPrimaries *prm)
> -{
> -    double delta;
> -
> -    for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) {
> -        const struct ColorPrimaries *ref = &color_primaries[p];
> -        if (!ref->prim.xr)
> -            continue;
> -
> -        delta = fabs(prm->prim.xr - ref->prim.xr) +
> -                fabs(prm->prim.yr - ref->prim.yr) +
> -                fabs(prm->prim.yg - ref->prim.yg) +
> -                fabs(prm->prim.yg - ref->prim.yg) +
> -                fabs(prm->prim.yb - ref->prim.yb) +
> -                fabs(prm->prim.yb - ref->prim.yb) +
> -                fabs(prm->wp.xw - ref->wp.xw) +
> -                fabs(prm->wp.yw - ref->wp.yw);
> -
> -        if (delta < 0.001)
> -            return p;
> -    }
> -
> -    return AVCOL_PRI_UNSPECIFIED;
> -}
> -
>   void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs,
>                              double rgb2yuv[3][3])
>   {
> diff --git a/libavfilter/colorspace.h b/libavfilter/colorspace.h
> index 6959133a49..c5f39baca8 100644
> --- a/libavfilter/colorspace.h
> +++ b/libavfilter/colorspace.h
> @@ -20,43 +20,20 @@
>   #ifndef AVFILTER_COLORSPACE_H
>   #define AVFILTER_COLORSPACE_H
>   
> +#include "libavutil/csp.h"
>   #include "libavutil/frame.h"
>   #include "libavutil/pixfmt.h"
>   
>   #define REFERENCE_WHITE 100.0f
>   
> -struct LumaCoefficients {
> -    double cr, cg, cb;
> -};
> -
> -struct PrimaryCoefficients {
> -    double xr, yr, xg, yg, xb, yb;
> -};
> -
> -struct WhitepointCoefficients {
> -    double xw, yw;
> -};
> -
> -struct ColorPrimaries {
> -    struct WhitepointCoefficients wp;
> -    struct PrimaryCoefficients prim;
> -};
> -
>   void ff_matrix_invert_3x3(const double in[3][3], double out[3][3]);
>   void ff_matrix_mul_3x3(double dst[3][3],
>                  const double src1[3][3], const double src2[3][3]);
>   void ff_fill_rgb2xyz_table(const struct PrimaryCoefficients *coeffs,
>                              const struct WhitepointCoefficients *wp,
>                              double rgb2xyz[3][3]);
> -
> -/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
> -enum AVColorPrimaries ff_detect_color_primaries(const struct ColorPrimaries *prm);
> -
> -const struct ColorPrimaries *ff_get_color_primaries(enum AVColorPrimaries prm);
> -const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp);
>   void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs,
>                              double rgb2yuv[3][3]);
> -
>   double ff_determine_signal_peak(AVFrame *in);
>   void ff_update_hdr_metadata(AVFrame *in, double peak);
>   
> diff --git a/libavfilter/fflcms2.c b/libavfilter/fflcms2.c
> index efc7cb5189..b1a0429010 100644
> --- a/libavfilter/fflcms2.c
> +++ b/libavfilter/fflcms2.c
> @@ -18,6 +18,7 @@
>    */
>   
>   #include "libavutil/color_utils.h"
> +#include "libavutil/csp.h"
>   
>   #include "fflcms2.h"
>   
> @@ -151,7 +152,7 @@ int ff_icc_profile_generate(FFIccContext *s,
>       const struct ColorPrimaries *prim;
>       int ret;
>   
> -    if (!(prim = ff_get_color_primaries(color_prim)))
> +    if (!(prim = av_get_color_primaries(color_prim)))
>           return AVERROR_INVALIDDATA;
>       if ((ret = get_curve(s, color_trc, &tonecurve)) < 0)
>           return ret;
> diff --git a/libavfilter/fflcms2.h b/libavfilter/fflcms2.h
> index ad6c8c47cf..628598a41c 100644
> --- a/libavfilter/fflcms2.h
> +++ b/libavfilter/fflcms2.h
> @@ -25,9 +25,9 @@
>   #ifndef AVFILTER_FFLCMS2_H
>   #define AVFILTER_FFLCMS2_H
>   
> +#include "libavutil/csp.h"
>   #include "libavutil/frame.h"
>   #include "libavutil/pixfmt.h"
> -#include "colorspace.h"
>   
>   #include <lcms2.h>
>   
> diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c
> index 3c8b3b20eb..e5b1a06c54 100644
> --- a/libavfilter/vf_colorspace.c
> +++ b/libavfilter/vf_colorspace.c
> @@ -24,6 +24,7 @@
>    */
>   
>   #include "libavutil/avassert.h"
> +#include "libavutil/csp.h"
>   #include "libavutil/mem_internal.h"
>   #include "libavutil/opt.h"
>   #include "libavutil/pixdesc.h"
> @@ -438,7 +439,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>               s->in_prm = default_prm[FFMIN(s->user_iall, CS_NB)];
>           if (s->user_iprm != AVCOL_PRI_UNSPECIFIED)
>               s->in_prm = s->user_iprm;
> -        s->in_primaries = ff_get_color_primaries(s->in_prm);
> +        s->in_primaries = av_get_color_primaries(s->in_prm);
>           if (!s->in_primaries) {
>               av_log(ctx, AV_LOG_ERROR,
>                      "Unsupported input primaries %d (%s)\n",
> @@ -446,7 +447,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>               return AVERROR(EINVAL);
>           }
>           s->out_prm = out->color_primaries;
> -        s->out_primaries = ff_get_color_primaries(s->out_prm);
> +        s->out_primaries = av_get_color_primaries(s->out_prm);
>           if (!s->out_primaries) {
>               if (s->out_prm == AVCOL_PRI_UNSPECIFIED) {
>                   if (s->user_all == CS_UNSPECIFIED) {
> @@ -551,7 +552,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>           s->in_rng = in->color_range;
>           if (s->user_irng != AVCOL_RANGE_UNSPECIFIED)
>               s->in_rng = s->user_irng;
> -        s->in_lumacoef = ff_get_luma_coefficients(s->in_csp);
> +        s->in_lumacoef = av_get_luma_coefficients(s->in_csp);
>           if (!s->in_lumacoef) {
>               av_log(ctx, AV_LOG_ERROR,
>                      "Unsupported input colorspace %d (%s)\n",
> @@ -564,7 +565,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>       if (!s->out_lumacoef) {
>           s->out_csp = out->colorspace;
>           s->out_rng = out->color_range;
> -        s->out_lumacoef = ff_get_luma_coefficients(s->out_csp);
> +        s->out_lumacoef = av_get_luma_coefficients(s->out_csp);
>           if (!s->out_lumacoef) {
>               if (s->out_csp == AVCOL_SPC_UNSPECIFIED) {
>                   if (s->user_all == CS_UNSPECIFIED) {
> diff --git a/libavfilter/vf_iccdetect.c b/libavfilter/vf_iccdetect.c
> index fb7871f035..d2b0e5569f 100644
> --- a/libavfilter/vf_iccdetect.c
> +++ b/libavfilter/vf_iccdetect.c
> @@ -24,6 +24,7 @@
>   
>   #include <lcms2.h>
>   
> +#include "libavutil/csp.h"
>   #include "libavutil/opt.h"
>   #include "libavutil/pixdesc.h"
>   
> @@ -98,7 +99,7 @@ static int iccdetect_filter_frame(AVFilterLink *inlink, AVFrame *frame)
>       if (ret < 0)
>           return ret;
>   
> -    s->profile_prim = ff_detect_color_primaries(&coeffs);
> +    s->profile_prim = av_detect_color_primaries(&coeffs);
>   
>   done:
>       if (s->profile_prim != AVCOL_PRI_UNSPECIFIED) {
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 234de62a4b..74d21a8103 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -20,6 +20,7 @@ HEADERS = adler32.h                                                     \
>             common.h                                                      \
>             cpu.h                                                         \
>             crc.h                                                         \
> +          csp.h                                                         \
>             des.h                                                         \
>             detection_bbox.h                                              \
>             dict.h                                                        \
> @@ -113,6 +114,7 @@ OBJS = adler32.o                                                        \
>          color_utils.o                                                    \
>          cpu.o                                                            \
>          crc.o                                                            \
> +       csp.o                                                            \
>          des.o                                                            \
>          detection_bbox.o                                                 \
>          dict.o                                                           \
> diff --git a/libavutil/csp.c b/libavutil/csp.c
> new file mode 100644
> index 0000000000..cd755c1795
> --- /dev/null
> +++ b/libavutil/csp.c
> @@ -0,0 +1,111 @@
> +/*
> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> + * 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 "csp.h"
> +#include "frame.h"
> +#include "mastering_display_metadata.h"
> +#include "pixfmt.h"
> +
> +/*
> + * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html
> + * The older ones (bt470bg/m) are also explained in their respective ITU docs
> + * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf)
> + * whereas the newer ones can typically be copied directly from wikipedia :)
> + */
> +static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
> +    [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
> +    [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
> +    [AVCOL_SPC_SMPTE170M]  = { 0.299,  0.587,  0.114  },
> +    [AVCOL_SPC_BT709]      = { 0.2126, 0.7152, 0.0722 },
> +    [AVCOL_SPC_SMPTE240M]  = { 0.212,  0.701,  0.087  },
> +    [AVCOL_SPC_YCOCG]      = { 0.25,   0.5,    0.25   },
> +    [AVCOL_SPC_RGB]        = { 1,      1,      1      },
> +    [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 },
> +    [AVCOL_SPC_BT2020_CL]  = { 0.2627, 0.6780, 0.0593 },
> +};
> +
> +const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp)
> +{
> +    const struct LumaCoefficients *coeffs;
> +
> +    if (csp >= AVCOL_SPC_NB)
> +        return NULL;
> +    coeffs = &luma_coefficients[csp];
> +    if (!coeffs->cr)
> +        return NULL;
> +
> +    return coeffs;
> +}
> +
> +#define WP_D65 { 0.3127, 0.3290 }
> +#define WP_C   { 0.3100, 0.3160 }
> +#define WP_DCI { 0.3140, 0.3510 }
> +#define WP_E   { 1/3.0f, 1/3.0f }
> +
> +static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = {
> +    [AVCOL_PRI_BT709]     = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } },
> +    [AVCOL_PRI_BT470M]    = { WP_C,   { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } },
> +    [AVCOL_PRI_BT470BG]   = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } },
> +    [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> +    [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> +    [AVCOL_PRI_SMPTE428]  = { WP_E,   { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } },
> +    [AVCOL_PRI_SMPTE431]  = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> +    [AVCOL_PRI_SMPTE432]  = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> +    [AVCOL_PRI_FILM]      = { WP_C,   { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } },
> +    [AVCOL_PRI_BT2020]    = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } },
> +    [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } },
> +};
> +
> +const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm)
> +{
> +    const struct ColorPrimaries *p;
> +
> +    if (prm >= AVCOL_PRI_NB)
> +        return NULL;
> +    p = &color_primaries[prm];
> +    if (!p->prim.xr)
> +        return NULL;
> +
> +    return p;
> +}
> +
> +enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm)
> +{
> +    double delta;
> +
> +    for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) {
> +        const struct ColorPrimaries *ref = &color_primaries[p];
> +        if (!ref->prim.xr)
> +            continue;
> +
> +        delta = fabs(prm->prim.xr - ref->prim.xr) +
> +                fabs(prm->prim.yr - ref->prim.yr) +
> +                fabs(prm->prim.yg - ref->prim.yg) +
> +                fabs(prm->prim.yg - ref->prim.yg) +
> +                fabs(prm->prim.yb - ref->prim.yb) +
> +                fabs(prm->prim.yb - ref->prim.yb) +
> +                fabs(prm->wp.xw - ref->wp.xw) +
> +                fabs(prm->wp.yw - ref->wp.yw);
> +
> +        if (delta < 0.001)
> +            return p;
> +    }
> +
> +    return AVCOL_PRI_UNSPECIFIED;
> +}
> diff --git a/libavutil/csp.h b/libavutil/csp.h
> new file mode 100644
> index 0000000000..1bcde7ddd3
> --- /dev/null
> +++ b/libavutil/csp.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> + * 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
> + */
> +
> +#ifndef AVUTIL_CSP_H
> +#define AVUTIL_CSP_H
> +
> +#include "libavutil/frame.h"
> +#include "libavutil/pixfmt.h"
> +
> +struct LumaCoefficients {
> +    double cr, cg, cb;
> +};
> +
> +struct PrimaryCoefficients {
> +    double xr, yr, xg, yg, xb, yb;
> +};
> +
> +struct WhitepointCoefficients {
> +    double xw, yw;
> +};
> +
> +struct ColorPrimaries {
> +    struct WhitepointCoefficients wp;
> +    struct PrimaryCoefficients prim;
> +};
> +
> +/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
> +enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm);
> +
> +const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm);
> +const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp);
> +
> +#endif /* AVUTIL_CSP_H */
Michael Niedermayer May 13, 2022, 9:22 p.m. UTC | #3
On Fri, May 13, 2022 at 11:42:08AM -0400, Leo Izen wrote:
> This commit moves some of the functionality from avfilter/colorspace
> into avutil/csp and exposes it as a public API so it can be used by
> libavcodec and/or libavformat.
[...]
> diff --git a/libavutil/csp.h b/libavutil/csp.h
> new file mode 100644
> index 0000000000..1bcde7ddd3
> --- /dev/null
> +++ b/libavutil/csp.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> + * 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
> + */
> +
> +#ifndef AVUTIL_CSP_H
> +#define AVUTIL_CSP_H
> +
> +#include "libavutil/frame.h"
> +#include "libavutil/pixfmt.h"
> +
> +struct LumaCoefficients {
> +    double cr, cg, cb;
> +};
> +
> +struct PrimaryCoefficients {
> +    double xr, yr, xg, yg, xb, yb;
> +};
> +
> +struct WhitepointCoefficients {
> +    double xw, yw;
> +};

I think we should avoid floating point so as to ensure reproduceable
results and simplify regerssion testing

thx

[...]
Leo Izen May 14, 2022, 2:41 a.m. UTC | #4
On 5/13/22 17:22, Michael Niedermayer wrote:
> On Fri, May 13, 2022 at 11:42:08AM -0400, Leo Izen wrote:
>> +
>> +struct WhitepointCoefficients {
>> +    double xw, yw;
>> +};
> I think we should avoid floating point so as to ensure reproduceable
> results and simplify regerssion testing
>
> thx
This code already exists in master right now in libavfilter/colorspace, 
so changing these from floats to AVRational would require a bit more 
work than just a movement.

- Leo Izen (thebombzen)
Leo Izen May 14, 2022, 2:43 a.m. UTC | #5
On 5/13/22 15:18, James Almer wrote:
> On 5/13/2022 12:42 PM, Leo Izen wrote:
>> This commit moves some of the functionality from avfilter/colorspace
>> into avutil/csp and exposes it as a public API so it can be used by
>> libavcodec and/or libavformat.
> 
> If it's of no use for library users, then make them avpriv_ and not 
> installed.

I was told a public API would be useful for this. I recall haasn and 
Lynne voicing support on IRC, but maybe I misinterpreted what they meant.

- Leo Izen (thebombzen)
Niklas Haas May 14, 2022, 12:15 p.m. UTC | #6
Hi,

If you push the code somewhere I can take a stab at porting it to
AVRational.

On Fri, 13 May 2022 22:41:15 -0400 Leo Izen <leo.izen@gmail.com> wrote:
> On 5/13/22 17:22, Michael Niedermayer wrote:
> > On Fri, May 13, 2022 at 11:42:08AM -0400, Leo Izen wrote:
> >> +
> >> +struct WhitepointCoefficients {
> >> +    double xw, yw;
> >> +};
> > I think we should avoid floating point so as to ensure reproduceable
> > results and simplify regerssion testing
> >
> > thx
> This code already exists in master right now in libavfilter/colorspace, 
> so changing these from floats to AVRational would require a bit more 
> work than just a movement.
> 
> - Leo Izen (thebombzen)
> 
> _______________________________________________
> 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".
Andreas Rheinhardt May 15, 2022, 4:32 p.m. UTC | #7
Leo Izen:
> This commit moves some of the functionality from avfilter/colorspace
> into avutil/csp and exposes it as a public API so it can be used by
> libavcodec and/or libavformat.
> ---
>  libavfilter/colorspace.c    |  88 ----------------------------
>  libavfilter/colorspace.h    |  25 +-------
>  libavfilter/fflcms2.c       |   3 +-
>  libavfilter/fflcms2.h       |   2 +-
>  libavfilter/vf_colorspace.c |   9 +--
>  libavfilter/vf_iccdetect.c  |   3 +-
>  libavutil/Makefile          |   2 +
>  libavutil/csp.c             | 111 ++++++++++++++++++++++++++++++++++++
>  libavutil/csp.h             |  49 ++++++++++++++++
>  9 files changed, 173 insertions(+), 119 deletions(-)
>  create mode 100644 libavutil/csp.c
>  create mode 100644 libavutil/csp.h
> 
> diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
> index 8d7b882375..f22e7002e1 100644
> --- a/libavfilter/colorspace.c
> +++ b/libavfilter/colorspace.c
> @@ -107,94 +107,6 @@ static const double gbr_matrix[3][3] =
>      { 0.5, -0.5, 0   },
>  };
>  
> -/*
> - * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html
> - * The older ones (bt470bg/m) are also explained in their respective ITU docs
> - * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf)
> - * whereas the newer ones can typically be copied directly from wikipedia :)
> - */
> -static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
> -    [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
> -    [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
> -    [AVCOL_SPC_SMPTE170M]  = { 0.299,  0.587,  0.114  },
> -    [AVCOL_SPC_BT709]      = { 0.2126, 0.7152, 0.0722 },
> -    [AVCOL_SPC_SMPTE240M]  = { 0.212,  0.701,  0.087  },
> -    [AVCOL_SPC_YCOCG]      = { 0.25,   0.5,    0.25   },
> -    [AVCOL_SPC_RGB]        = { 1,      1,      1      },
> -    [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 },
> -    [AVCOL_SPC_BT2020_CL]  = { 0.2627, 0.6780, 0.0593 },
> -};
> -
> -const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp)
> -{
> -    const struct LumaCoefficients *coeffs;
> -
> -    if (csp >= AVCOL_SPC_NB)
> -        return NULL;
> -    coeffs = &luma_coefficients[csp];
> -    if (!coeffs->cr)
> -        return NULL;
> -
> -    return coeffs;
> -}
> -
> -#define WP_D65 { 0.3127, 0.3290 }
> -#define WP_C   { 0.3100, 0.3160 }
> -#define WP_DCI { 0.3140, 0.3510 }
> -#define WP_E   { 1/3.0f, 1/3.0f }
> -
> -static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = {
> -    [AVCOL_PRI_BT709]     = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } },
> -    [AVCOL_PRI_BT470M]    = { WP_C,   { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } },
> -    [AVCOL_PRI_BT470BG]   = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } },
> -    [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> -    [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> -    [AVCOL_PRI_SMPTE428]  = { WP_E,   { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } },
> -    [AVCOL_PRI_SMPTE431]  = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> -    [AVCOL_PRI_SMPTE432]  = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> -    [AVCOL_PRI_FILM]      = { WP_C,   { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } },
> -    [AVCOL_PRI_BT2020]    = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } },
> -    [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } },
> -};
> -
> -const struct ColorPrimaries *ff_get_color_primaries(enum AVColorPrimaries prm)
> -{
> -    const struct ColorPrimaries *p;
> -
> -    if (prm >= AVCOL_PRI_NB)
> -        return NULL;
> -    p = &color_primaries[prm];
> -    if (!p->prim.xr)
> -        return NULL;
> -
> -    return p;
> -}
> -
> -enum AVColorPrimaries ff_detect_color_primaries(const struct ColorPrimaries *prm)
> -{
> -    double delta;
> -
> -    for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) {
> -        const struct ColorPrimaries *ref = &color_primaries[p];
> -        if (!ref->prim.xr)
> -            continue;
> -
> -        delta = fabs(prm->prim.xr - ref->prim.xr) +
> -                fabs(prm->prim.yr - ref->prim.yr) +
> -                fabs(prm->prim.yg - ref->prim.yg) +
> -                fabs(prm->prim.yg - ref->prim.yg) +
> -                fabs(prm->prim.yb - ref->prim.yb) +
> -                fabs(prm->prim.yb - ref->prim.yb) +
> -                fabs(prm->wp.xw - ref->wp.xw) +
> -                fabs(prm->wp.yw - ref->wp.yw);
> -
> -        if (delta < 0.001)
> -            return p;
> -    }
> -
> -    return AVCOL_PRI_UNSPECIFIED;
> -}
> -
>  void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs,
>                             double rgb2yuv[3][3])
>  {
> diff --git a/libavfilter/colorspace.h b/libavfilter/colorspace.h
> index 6959133a49..c5f39baca8 100644
> --- a/libavfilter/colorspace.h
> +++ b/libavfilter/colorspace.h
> @@ -20,43 +20,20 @@
>  #ifndef AVFILTER_COLORSPACE_H
>  #define AVFILTER_COLORSPACE_H
>  
> +#include "libavutil/csp.h"
>  #include "libavutil/frame.h"
>  #include "libavutil/pixfmt.h"
>  
>  #define REFERENCE_WHITE 100.0f
>  
> -struct LumaCoefficients {
> -    double cr, cg, cb;
> -};
> -
> -struct PrimaryCoefficients {
> -    double xr, yr, xg, yg, xb, yb;
> -};
> -
> -struct WhitepointCoefficients {
> -    double xw, yw;
> -};
> -
> -struct ColorPrimaries {
> -    struct WhitepointCoefficients wp;
> -    struct PrimaryCoefficients prim;
> -};
> -
>  void ff_matrix_invert_3x3(const double in[3][3], double out[3][3]);
>  void ff_matrix_mul_3x3(double dst[3][3],
>                 const double src1[3][3], const double src2[3][3]);
>  void ff_fill_rgb2xyz_table(const struct PrimaryCoefficients *coeffs,
>                             const struct WhitepointCoefficients *wp,
>                             double rgb2xyz[3][3]);
> -
> -/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
> -enum AVColorPrimaries ff_detect_color_primaries(const struct ColorPrimaries *prm);
> -
> -const struct ColorPrimaries *ff_get_color_primaries(enum AVColorPrimaries prm);
> -const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp);
>  void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs,
>                             double rgb2yuv[3][3]);
> -
>  double ff_determine_signal_peak(AVFrame *in);
>  void ff_update_hdr_metadata(AVFrame *in, double peak);
>  
> diff --git a/libavfilter/fflcms2.c b/libavfilter/fflcms2.c
> index efc7cb5189..b1a0429010 100644
> --- a/libavfilter/fflcms2.c
> +++ b/libavfilter/fflcms2.c
> @@ -18,6 +18,7 @@
>   */
>  
>  #include "libavutil/color_utils.h"
> +#include "libavutil/csp.h"
>  
>  #include "fflcms2.h"
>  
> @@ -151,7 +152,7 @@ int ff_icc_profile_generate(FFIccContext *s,
>      const struct ColorPrimaries *prim;
>      int ret;
>  
> -    if (!(prim = ff_get_color_primaries(color_prim)))
> +    if (!(prim = av_get_color_primaries(color_prim)))
>          return AVERROR_INVALIDDATA;
>      if ((ret = get_curve(s, color_trc, &tonecurve)) < 0)
>          return ret;
> diff --git a/libavfilter/fflcms2.h b/libavfilter/fflcms2.h
> index ad6c8c47cf..628598a41c 100644
> --- a/libavfilter/fflcms2.h
> +++ b/libavfilter/fflcms2.h
> @@ -25,9 +25,9 @@
>  #ifndef AVFILTER_FFLCMS2_H
>  #define AVFILTER_FFLCMS2_H
>  
> +#include "libavutil/csp.h"
>  #include "libavutil/frame.h"
>  #include "libavutil/pixfmt.h"
> -#include "colorspace.h"
>  
>  #include <lcms2.h>
>  
> diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c
> index 3c8b3b20eb..e5b1a06c54 100644
> --- a/libavfilter/vf_colorspace.c
> +++ b/libavfilter/vf_colorspace.c
> @@ -24,6 +24,7 @@
>   */
>  
>  #include "libavutil/avassert.h"
> +#include "libavutil/csp.h"
>  #include "libavutil/mem_internal.h"
>  #include "libavutil/opt.h"
>  #include "libavutil/pixdesc.h"
> @@ -438,7 +439,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>              s->in_prm = default_prm[FFMIN(s->user_iall, CS_NB)];
>          if (s->user_iprm != AVCOL_PRI_UNSPECIFIED)
>              s->in_prm = s->user_iprm;
> -        s->in_primaries = ff_get_color_primaries(s->in_prm);
> +        s->in_primaries = av_get_color_primaries(s->in_prm);
>          if (!s->in_primaries) {
>              av_log(ctx, AV_LOG_ERROR,
>                     "Unsupported input primaries %d (%s)\n",
> @@ -446,7 +447,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>              return AVERROR(EINVAL);
>          }
>          s->out_prm = out->color_primaries;
> -        s->out_primaries = ff_get_color_primaries(s->out_prm);
> +        s->out_primaries = av_get_color_primaries(s->out_prm);
>          if (!s->out_primaries) {
>              if (s->out_prm == AVCOL_PRI_UNSPECIFIED) {
>                  if (s->user_all == CS_UNSPECIFIED) {
> @@ -551,7 +552,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>          s->in_rng = in->color_range;
>          if (s->user_irng != AVCOL_RANGE_UNSPECIFIED)
>              s->in_rng = s->user_irng;
> -        s->in_lumacoef = ff_get_luma_coefficients(s->in_csp);
> +        s->in_lumacoef = av_get_luma_coefficients(s->in_csp);
>          if (!s->in_lumacoef) {
>              av_log(ctx, AV_LOG_ERROR,
>                     "Unsupported input colorspace %d (%s)\n",
> @@ -564,7 +565,7 @@ static int create_filtergraph(AVFilterContext *ctx,
>      if (!s->out_lumacoef) {
>          s->out_csp = out->colorspace;
>          s->out_rng = out->color_range;
> -        s->out_lumacoef = ff_get_luma_coefficients(s->out_csp);
> +        s->out_lumacoef = av_get_luma_coefficients(s->out_csp);
>          if (!s->out_lumacoef) {
>              if (s->out_csp == AVCOL_SPC_UNSPECIFIED) {
>                  if (s->user_all == CS_UNSPECIFIED) {
> diff --git a/libavfilter/vf_iccdetect.c b/libavfilter/vf_iccdetect.c
> index fb7871f035..d2b0e5569f 100644
> --- a/libavfilter/vf_iccdetect.c
> +++ b/libavfilter/vf_iccdetect.c
> @@ -24,6 +24,7 @@
>  
>  #include <lcms2.h>
>  
> +#include "libavutil/csp.h"
>  #include "libavutil/opt.h"
>  #include "libavutil/pixdesc.h"
>  
> @@ -98,7 +99,7 @@ static int iccdetect_filter_frame(AVFilterLink *inlink, AVFrame *frame)
>      if (ret < 0)
>          return ret;
>  
> -    s->profile_prim = ff_detect_color_primaries(&coeffs);
> +    s->profile_prim = av_detect_color_primaries(&coeffs);
>  
>  done:
>      if (s->profile_prim != AVCOL_PRI_UNSPECIFIED) {
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 234de62a4b..74d21a8103 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -20,6 +20,7 @@ HEADERS = adler32.h                                                     \
>            common.h                                                      \
>            cpu.h                                                         \
>            crc.h                                                         \
> +          csp.h                                                         \
>            des.h                                                         \
>            detection_bbox.h                                              \
>            dict.h                                                        \
> @@ -113,6 +114,7 @@ OBJS = adler32.o                                                        \
>         color_utils.o                                                    \
>         cpu.o                                                            \
>         crc.o                                                            \
> +       csp.o                                                            \
>         des.o                                                            \
>         detection_bbox.o                                                 \
>         dict.o                                                           \
> diff --git a/libavutil/csp.c b/libavutil/csp.c
> new file mode 100644
> index 0000000000..cd755c1795
> --- /dev/null
> +++ b/libavutil/csp.c
> @@ -0,0 +1,111 @@
> +/*
> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> + * 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 "csp.h"
> +#include "frame.h"
> +#include "mastering_display_metadata.h"
> +#include "pixfmt.h"
> +
> +/*
> + * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html
> + * The older ones (bt470bg/m) are also explained in their respective ITU docs
> + * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf)
> + * whereas the newer ones can typically be copied directly from wikipedia :)
> + */
> +static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
> +    [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
> +    [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
> +    [AVCOL_SPC_SMPTE170M]  = { 0.299,  0.587,  0.114  },
> +    [AVCOL_SPC_BT709]      = { 0.2126, 0.7152, 0.0722 },
> +    [AVCOL_SPC_SMPTE240M]  = { 0.212,  0.701,  0.087  },
> +    [AVCOL_SPC_YCOCG]      = { 0.25,   0.5,    0.25   },
> +    [AVCOL_SPC_RGB]        = { 1,      1,      1      },
> +    [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 },
> +    [AVCOL_SPC_BT2020_CL]  = { 0.2627, 0.6780, 0.0593 },
> +};
> +
> +const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp)
> +{
> +    const struct LumaCoefficients *coeffs;
> +
> +    if (csp >= AVCOL_SPC_NB)
> +        return NULL;
> +    coeffs = &luma_coefficients[csp];
> +    if (!coeffs->cr)
> +        return NULL;
> +
> +    return coeffs;
> +}
> +
> +#define WP_D65 { 0.3127, 0.3290 }
> +#define WP_C   { 0.3100, 0.3160 }
> +#define WP_DCI { 0.3140, 0.3510 }
> +#define WP_E   { 1/3.0f, 1/3.0f }
> +
> +static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = {
> +    [AVCOL_PRI_BT709]     = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } },
> +    [AVCOL_PRI_BT470M]    = { WP_C,   { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } },
> +    [AVCOL_PRI_BT470BG]   = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } },
> +    [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> +    [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
> +    [AVCOL_PRI_SMPTE428]  = { WP_E,   { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } },
> +    [AVCOL_PRI_SMPTE431]  = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> +    [AVCOL_PRI_SMPTE432]  = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
> +    [AVCOL_PRI_FILM]      = { WP_C,   { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } },
> +    [AVCOL_PRI_BT2020]    = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } },
> +    [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } },
> +};
> +
> +const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm)
> +{
> +    const struct ColorPrimaries *p;
> +
> +    if (prm >= AVCOL_PRI_NB)
> +        return NULL;
> +    p = &color_primaries[prm];
> +    if (!p->prim.xr)
> +        return NULL;
> +
> +    return p;
> +}
> +
> +enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm)
> +{
> +    double delta;
> +
> +    for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) {
> +        const struct ColorPrimaries *ref = &color_primaries[p];
> +        if (!ref->prim.xr)
> +            continue;
> +
> +        delta = fabs(prm->prim.xr - ref->prim.xr) +
> +                fabs(prm->prim.yr - ref->prim.yr) +
> +                fabs(prm->prim.yg - ref->prim.yg) +
> +                fabs(prm->prim.yg - ref->prim.yg) +
> +                fabs(prm->prim.yb - ref->prim.yb) +
> +                fabs(prm->prim.yb - ref->prim.yb) +
> +                fabs(prm->wp.xw - ref->wp.xw) +
> +                fabs(prm->wp.yw - ref->wp.yw);
> +
> +        if (delta < 0.001)
> +            return p;
> +    }
> +
> +    return AVCOL_PRI_UNSPECIFIED;
> +}
> diff --git a/libavutil/csp.h b/libavutil/csp.h
> new file mode 100644
> index 0000000000..1bcde7ddd3
> --- /dev/null
> +++ b/libavutil/csp.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> + * 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
> + */
> +
> +#ifndef AVUTIL_CSP_H
> +#define AVUTIL_CSP_H
> +
> +#include "libavutil/frame.h"

?

> +#include "libavutil/pixfmt.h"
> +
> +struct LumaCoefficients {
> +    double cr, cg, cb;
> +};
> +
> +struct PrimaryCoefficients {
> +    double xr, yr, xg, yg, xb, yb;
> +};
> +
> +struct WhitepointCoefficients {
> +    double xw, yw;
> +};
> +
> +struct ColorPrimaries {
> +    struct WhitepointCoefficients wp;
> +    struct PrimaryCoefficients prim;
> +};
> +
> +/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
> +enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm);
> +
> +const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm);
> +const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp);
> +
> +#endif /* AVUTIL_CSP_H */

Is there any scenario in which these structs might need to be extended?
This is something that we could no longer easily do if these structs
were public.

- Andreas
Ronald S. Bultje May 15, 2022, 4:49 p.m. UTC | #8
Hi,

On Fri, May 13, 2022 at 5:22 PM Michael Niedermayer <michael@niedermayer.cc>
wrote:

> On Fri, May 13, 2022 at 11:42:08AM -0400, Leo Izen wrote:
> > This commit moves some of the functionality from avfilter/colorspace
> > into avutil/csp and exposes it as a public API so it can be used by
> > libavcodec and/or libavformat.
> [...]
> > diff --git a/libavutil/csp.h b/libavutil/csp.h
> > new file mode 100644
> > index 0000000000..1bcde7ddd3
> > --- /dev/null
> > +++ b/libavutil/csp.h
> > @@ -0,0 +1,49 @@
> > +/*
> > + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> > + * 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
> > + */
> > +
> > +#ifndef AVUTIL_CSP_H
> > +#define AVUTIL_CSP_H
> > +
> > +#include "libavutil/frame.h"
> > +#include "libavutil/pixfmt.h"
> > +
> > +struct LumaCoefficients {
> > +    double cr, cg, cb;
> > +};
> > +
> > +struct PrimaryCoefficients {
> > +    double xr, yr, xg, yg, xb, yb;
> > +};
> > +
> > +struct WhitepointCoefficients {
> > +    double xw, yw;
> > +};
>
> I think we should avoid floating point so as to ensure reproduceable
> results and simplify regerssion testing
>

To explain: when I designed this stuff, I chose to keep them in float so
that we can use the literal values from the specs, which are themselves in
floating point. That would not be possible anymore, and would therefore
make it slightly harder to read for a casual observer.

(Otherwise no opinion, I'm typically used to fixed-point rather than
floating-point myself also.)

Ronald
Niklas Haas May 15, 2022, 6:10 p.m. UTC | #9
On Sun, 15 May 2022 12:49:51 -0400 "Ronald S. Bultje" <rsbultje@gmail.com> wrote:
> To explain: when I designed this stuff, I chose to keep them in float so
> that we can use the literal values from the specs, which are themselves in
> floating point. That would not be possible anymore, and would therefore
> make it slightly harder to read for a casual observer.
> 
> (Otherwise no opinion, I'm typically used to fixed-point rather than
> floating-point myself also.)
> 
> Ronald

Can you elaborate on this? Aren't almost all of these constants
represented in some notation rounded to 3-4 decimal places, in which
case a fixed point notation with denominator 10^N makes perfect sense?
Michael Niedermayer May 15, 2022, 6:55 p.m. UTC | #10
On Sun, May 15, 2022 at 12:49:51PM -0400, Ronald S. Bultje wrote:
> Hi,
> 
> On Fri, May 13, 2022 at 5:22 PM Michael Niedermayer <michael@niedermayer.cc>
> wrote:
> 
> > On Fri, May 13, 2022 at 11:42:08AM -0400, Leo Izen wrote:
> > > This commit moves some of the functionality from avfilter/colorspace
> > > into avutil/csp and exposes it as a public API so it can be used by
> > > libavcodec and/or libavformat.
> > [...]
> > > diff --git a/libavutil/csp.h b/libavutil/csp.h
> > > new file mode 100644
> > > index 0000000000..1bcde7ddd3
> > > --- /dev/null
> > > +++ b/libavutil/csp.h
> > > @@ -0,0 +1,49 @@
> > > +/*
> > > + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> > > + * 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
> > > + */
> > > +
> > > +#ifndef AVUTIL_CSP_H
> > > +#define AVUTIL_CSP_H
> > > +
> > > +#include "libavutil/frame.h"
> > > +#include "libavutil/pixfmt.h"
> > > +
> > > +struct LumaCoefficients {
> > > +    double cr, cg, cb;
> > > +};
> > > +
> > > +struct PrimaryCoefficients {
> > > +    double xr, yr, xg, yg, xb, yb;
> > > +};
> > > +
> > > +struct WhitepointCoefficients {
> > > +    double xw, yw;
> > > +};
> >
> > I think we should avoid floating point so as to ensure reproduceable
> > results and simplify regerssion testing
> >
> 
> To explain: when I designed this stuff, I chose to keep them in float so
> that we can use the literal values from the specs, which are themselves in
> floating point. That would not be possible anymore, and would therefore
> make it slightly harder to read for a casual observer.
> 
> (Otherwise no opinion, I'm typically used to fixed-point rather than
> floating-point myself also.)

I looked at Rec. ITU-T H.264 (02/2016) (was the first thing laying around,
i assume but did not check that this matches the specs these numbers came from)

(randomly picking "whitepoints")
the whitepoints for "10" contain some 1/3 values
but if i just look at "1" the values are
0.3127, 0.3290
i dont think these can be represented as m*2^E either
3127/10000 = m*2^E
3127 * 2^-E = m * 10000
both sides would be all integers
the right side contains 5 as factor, the left doesnt

of course i may be missing something

thx

[...]
Michael Niedermayer May 15, 2022, 7:19 p.m. UTC | #11
On Sun, May 15, 2022 at 08:55:49PM +0200, Michael Niedermayer wrote:
> On Sun, May 15, 2022 at 12:49:51PM -0400, Ronald S. Bultje wrote:
> > Hi,
> > 
> > On Fri, May 13, 2022 at 5:22 PM Michael Niedermayer <michael@niedermayer.cc>
> > wrote:
> > 
> > > On Fri, May 13, 2022 at 11:42:08AM -0400, Leo Izen wrote:
> > > > This commit moves some of the functionality from avfilter/colorspace
> > > > into avutil/csp and exposes it as a public API so it can be used by
> > > > libavcodec and/or libavformat.
> > > [...]
> > > > diff --git a/libavutil/csp.h b/libavutil/csp.h
> > > > new file mode 100644
> > > > index 0000000000..1bcde7ddd3
> > > > --- /dev/null
> > > > +++ b/libavutil/csp.h
> > > > @@ -0,0 +1,49 @@
> > > > +/*
> > > > + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
> > > > + * 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
> > > > + */
> > > > +
> > > > +#ifndef AVUTIL_CSP_H
> > > > +#define AVUTIL_CSP_H
> > > > +
> > > > +#include "libavutil/frame.h"
> > > > +#include "libavutil/pixfmt.h"
> > > > +
> > > > +struct LumaCoefficients {
> > > > +    double cr, cg, cb;
> > > > +};
> > > > +
> > > > +struct PrimaryCoefficients {
> > > > +    double xr, yr, xg, yg, xb, yb;
> > > > +};
> > > > +
> > > > +struct WhitepointCoefficients {
> > > > +    double xw, yw;
> > > > +};
> > >
> > > I think we should avoid floating point so as to ensure reproduceable
> > > results and simplify regerssion testing
> > >
> > 
> > To explain: when I designed this stuff, I chose to keep them in float so
> > that we can use the literal values from the specs, which are themselves in
> > floating point. That would not be possible anymore, and would therefore
> > make it slightly harder to read for a casual observer.
> > 
> > (Otherwise no opinion, I'm typically used to fixed-point rather than
> > floating-point myself also.)
> 
> I looked at Rec. ITU-T H.264 (02/2016) (was the first thing laying around,
> i assume but did not check that this matches the specs these numbers came from)
> 
> (randomly picking "whitepoints")
> the whitepoints for "10" contain some 1/3 values
> but if i just look at "1" the values are
> 0.3127, 0.3290
> i dont think these can be represented as m*2^E either
> 3127/10000 = m*2^E
> 3127 * 2^-E = m * 10000
> both sides would be all integers
> the right side contains 5 as factor, the left doesnt
> 
> of course i may be missing something

Also for extra entertainment try this:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    float exact_tenth = 0.1;
    double done = 1.0;
    float fone = 1.0;
    int i;

    for(i= 0; i<100000000; i++) {
        done *= exact_tenth * 10.0;
        fone *= exact_tenth * 10.0;
    }

    printf("float one is %f double one is %f\n", fone, done);

    return 0;
}


[...]
Leo Izen May 16, 2022, 2:45 p.m. UTC | #12
On 5/15/22 12:32, Andreas Rheinhardt wrote:
> Leo Izen:
>> +/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
>> +enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm);
>> +
>> +const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm);
>> +const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp);
>> +
>> +#endif /* AVUTIL_CSP_H */
> 
> Is there any scenario in which these structs might need to be extended?
> This is something that we could no longer easily do if these structs
> were public.
> 

I don't believe these will need to be extended since they're somewhat 
simple structs that are meant to contain a very specific set of data, 
not general data about a more abstract object.

- Leo Izen (thebombzen)
Niklas Haas May 18, 2022, 12:21 p.m. UTC | #13
On Sun, 15 May 2022 18:32:36 +0200 Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> Is there any scenario in which these structs might need to be extended?
> This is something that we could no longer easily do if these structs
> were public.

This struct has existed in essentially this exact form for decades
(before FFmpeg) and is derived from fundamentals of the human visual
system. I could not begin to dream of a reason it would need to be
suddenly extended - even if we add support for, say, CMYK color spaces
and libavprinter, it would be a new struct.
Niklas Haas May 18, 2022, 12:29 p.m. UTC | #14
On Wed, 18 May 2022 14:21:41 +0200 Niklas Haas <ffmpeg@haasn.xyz> wrote:
> On Sun, 15 May 2022 18:32:36 +0200 Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> > Is there any scenario in which these structs might need to be extended?
> > This is something that we could no longer easily do if these structs
> > were public.
> 
> This struct has existed in essentially this exact form for decades
> (before FFmpeg) and is derived from fundamentals of the human visual
> system. I could not begin to dream of a reason it would need to be
> suddenly extended - even if we add support for, say, CMYK color spaces
> and libavprinter, it would be a new struct.

That said, I think that it might make more sense, for reasons of polish,
to group the x/y coordinates into their own struct CIExy or something
along those lines.

Then you can also have helper functions accepting individual CIExy
struct elements. But YMMV.
diff mbox series

Patch

diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c
index 8d7b882375..f22e7002e1 100644
--- a/libavfilter/colorspace.c
+++ b/libavfilter/colorspace.c
@@ -107,94 +107,6 @@  static const double gbr_matrix[3][3] =
     { 0.5, -0.5, 0   },
 };
 
-/*
- * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html
- * The older ones (bt470bg/m) are also explained in their respective ITU docs
- * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf)
- * whereas the newer ones can typically be copied directly from wikipedia :)
- */
-static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
-    [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
-    [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
-    [AVCOL_SPC_SMPTE170M]  = { 0.299,  0.587,  0.114  },
-    [AVCOL_SPC_BT709]      = { 0.2126, 0.7152, 0.0722 },
-    [AVCOL_SPC_SMPTE240M]  = { 0.212,  0.701,  0.087  },
-    [AVCOL_SPC_YCOCG]      = { 0.25,   0.5,    0.25   },
-    [AVCOL_SPC_RGB]        = { 1,      1,      1      },
-    [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 },
-    [AVCOL_SPC_BT2020_CL]  = { 0.2627, 0.6780, 0.0593 },
-};
-
-const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp)
-{
-    const struct LumaCoefficients *coeffs;
-
-    if (csp >= AVCOL_SPC_NB)
-        return NULL;
-    coeffs = &luma_coefficients[csp];
-    if (!coeffs->cr)
-        return NULL;
-
-    return coeffs;
-}
-
-#define WP_D65 { 0.3127, 0.3290 }
-#define WP_C   { 0.3100, 0.3160 }
-#define WP_DCI { 0.3140, 0.3510 }
-#define WP_E   { 1/3.0f, 1/3.0f }
-
-static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = {
-    [AVCOL_PRI_BT709]     = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } },
-    [AVCOL_PRI_BT470M]    = { WP_C,   { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } },
-    [AVCOL_PRI_BT470BG]   = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } },
-    [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
-    [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
-    [AVCOL_PRI_SMPTE428]  = { WP_E,   { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } },
-    [AVCOL_PRI_SMPTE431]  = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
-    [AVCOL_PRI_SMPTE432]  = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
-    [AVCOL_PRI_FILM]      = { WP_C,   { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } },
-    [AVCOL_PRI_BT2020]    = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } },
-    [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } },
-};
-
-const struct ColorPrimaries *ff_get_color_primaries(enum AVColorPrimaries prm)
-{
-    const struct ColorPrimaries *p;
-
-    if (prm >= AVCOL_PRI_NB)
-        return NULL;
-    p = &color_primaries[prm];
-    if (!p->prim.xr)
-        return NULL;
-
-    return p;
-}
-
-enum AVColorPrimaries ff_detect_color_primaries(const struct ColorPrimaries *prm)
-{
-    double delta;
-
-    for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) {
-        const struct ColorPrimaries *ref = &color_primaries[p];
-        if (!ref->prim.xr)
-            continue;
-
-        delta = fabs(prm->prim.xr - ref->prim.xr) +
-                fabs(prm->prim.yr - ref->prim.yr) +
-                fabs(prm->prim.yg - ref->prim.yg) +
-                fabs(prm->prim.yg - ref->prim.yg) +
-                fabs(prm->prim.yb - ref->prim.yb) +
-                fabs(prm->prim.yb - ref->prim.yb) +
-                fabs(prm->wp.xw - ref->wp.xw) +
-                fabs(prm->wp.yw - ref->wp.yw);
-
-        if (delta < 0.001)
-            return p;
-    }
-
-    return AVCOL_PRI_UNSPECIFIED;
-}
-
 void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs,
                            double rgb2yuv[3][3])
 {
diff --git a/libavfilter/colorspace.h b/libavfilter/colorspace.h
index 6959133a49..c5f39baca8 100644
--- a/libavfilter/colorspace.h
+++ b/libavfilter/colorspace.h
@@ -20,43 +20,20 @@ 
 #ifndef AVFILTER_COLORSPACE_H
 #define AVFILTER_COLORSPACE_H
 
+#include "libavutil/csp.h"
 #include "libavutil/frame.h"
 #include "libavutil/pixfmt.h"
 
 #define REFERENCE_WHITE 100.0f
 
-struct LumaCoefficients {
-    double cr, cg, cb;
-};
-
-struct PrimaryCoefficients {
-    double xr, yr, xg, yg, xb, yb;
-};
-
-struct WhitepointCoefficients {
-    double xw, yw;
-};
-
-struct ColorPrimaries {
-    struct WhitepointCoefficients wp;
-    struct PrimaryCoefficients prim;
-};
-
 void ff_matrix_invert_3x3(const double in[3][3], double out[3][3]);
 void ff_matrix_mul_3x3(double dst[3][3],
                const double src1[3][3], const double src2[3][3]);
 void ff_fill_rgb2xyz_table(const struct PrimaryCoefficients *coeffs,
                            const struct WhitepointCoefficients *wp,
                            double rgb2xyz[3][3]);
-
-/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
-enum AVColorPrimaries ff_detect_color_primaries(const struct ColorPrimaries *prm);
-
-const struct ColorPrimaries *ff_get_color_primaries(enum AVColorPrimaries prm);
-const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp);
 void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs,
                            double rgb2yuv[3][3]);
-
 double ff_determine_signal_peak(AVFrame *in);
 void ff_update_hdr_metadata(AVFrame *in, double peak);
 
diff --git a/libavfilter/fflcms2.c b/libavfilter/fflcms2.c
index efc7cb5189..b1a0429010 100644
--- a/libavfilter/fflcms2.c
+++ b/libavfilter/fflcms2.c
@@ -18,6 +18,7 @@ 
  */
 
 #include "libavutil/color_utils.h"
+#include "libavutil/csp.h"
 
 #include "fflcms2.h"
 
@@ -151,7 +152,7 @@  int ff_icc_profile_generate(FFIccContext *s,
     const struct ColorPrimaries *prim;
     int ret;
 
-    if (!(prim = ff_get_color_primaries(color_prim)))
+    if (!(prim = av_get_color_primaries(color_prim)))
         return AVERROR_INVALIDDATA;
     if ((ret = get_curve(s, color_trc, &tonecurve)) < 0)
         return ret;
diff --git a/libavfilter/fflcms2.h b/libavfilter/fflcms2.h
index ad6c8c47cf..628598a41c 100644
--- a/libavfilter/fflcms2.h
+++ b/libavfilter/fflcms2.h
@@ -25,9 +25,9 @@ 
 #ifndef AVFILTER_FFLCMS2_H
 #define AVFILTER_FFLCMS2_H
 
+#include "libavutil/csp.h"
 #include "libavutil/frame.h"
 #include "libavutil/pixfmt.h"
-#include "colorspace.h"
 
 #include <lcms2.h>
 
diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c
index 3c8b3b20eb..e5b1a06c54 100644
--- a/libavfilter/vf_colorspace.c
+++ b/libavfilter/vf_colorspace.c
@@ -24,6 +24,7 @@ 
  */
 
 #include "libavutil/avassert.h"
+#include "libavutil/csp.h"
 #include "libavutil/mem_internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
@@ -438,7 +439,7 @@  static int create_filtergraph(AVFilterContext *ctx,
             s->in_prm = default_prm[FFMIN(s->user_iall, CS_NB)];
         if (s->user_iprm != AVCOL_PRI_UNSPECIFIED)
             s->in_prm = s->user_iprm;
-        s->in_primaries = ff_get_color_primaries(s->in_prm);
+        s->in_primaries = av_get_color_primaries(s->in_prm);
         if (!s->in_primaries) {
             av_log(ctx, AV_LOG_ERROR,
                    "Unsupported input primaries %d (%s)\n",
@@ -446,7 +447,7 @@  static int create_filtergraph(AVFilterContext *ctx,
             return AVERROR(EINVAL);
         }
         s->out_prm = out->color_primaries;
-        s->out_primaries = ff_get_color_primaries(s->out_prm);
+        s->out_primaries = av_get_color_primaries(s->out_prm);
         if (!s->out_primaries) {
             if (s->out_prm == AVCOL_PRI_UNSPECIFIED) {
                 if (s->user_all == CS_UNSPECIFIED) {
@@ -551,7 +552,7 @@  static int create_filtergraph(AVFilterContext *ctx,
         s->in_rng = in->color_range;
         if (s->user_irng != AVCOL_RANGE_UNSPECIFIED)
             s->in_rng = s->user_irng;
-        s->in_lumacoef = ff_get_luma_coefficients(s->in_csp);
+        s->in_lumacoef = av_get_luma_coefficients(s->in_csp);
         if (!s->in_lumacoef) {
             av_log(ctx, AV_LOG_ERROR,
                    "Unsupported input colorspace %d (%s)\n",
@@ -564,7 +565,7 @@  static int create_filtergraph(AVFilterContext *ctx,
     if (!s->out_lumacoef) {
         s->out_csp = out->colorspace;
         s->out_rng = out->color_range;
-        s->out_lumacoef = ff_get_luma_coefficients(s->out_csp);
+        s->out_lumacoef = av_get_luma_coefficients(s->out_csp);
         if (!s->out_lumacoef) {
             if (s->out_csp == AVCOL_SPC_UNSPECIFIED) {
                 if (s->user_all == CS_UNSPECIFIED) {
diff --git a/libavfilter/vf_iccdetect.c b/libavfilter/vf_iccdetect.c
index fb7871f035..d2b0e5569f 100644
--- a/libavfilter/vf_iccdetect.c
+++ b/libavfilter/vf_iccdetect.c
@@ -24,6 +24,7 @@ 
 
 #include <lcms2.h>
 
+#include "libavutil/csp.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 
@@ -98,7 +99,7 @@  static int iccdetect_filter_frame(AVFilterLink *inlink, AVFrame *frame)
     if (ret < 0)
         return ret;
 
-    s->profile_prim = ff_detect_color_primaries(&coeffs);
+    s->profile_prim = av_detect_color_primaries(&coeffs);
 
 done:
     if (s->profile_prim != AVCOL_PRI_UNSPECIFIED) {
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 234de62a4b..74d21a8103 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -20,6 +20,7 @@  HEADERS = adler32.h                                                     \
           common.h                                                      \
           cpu.h                                                         \
           crc.h                                                         \
+          csp.h                                                         \
           des.h                                                         \
           detection_bbox.h                                              \
           dict.h                                                        \
@@ -113,6 +114,7 @@  OBJS = adler32.o                                                        \
        color_utils.o                                                    \
        cpu.o                                                            \
        crc.o                                                            \
+       csp.o                                                            \
        des.o                                                            \
        detection_bbox.o                                                 \
        dict.o                                                           \
diff --git a/libavutil/csp.c b/libavutil/csp.c
new file mode 100644
index 0000000000..cd755c1795
--- /dev/null
+++ b/libavutil/csp.c
@@ -0,0 +1,111 @@ 
+/*
+ * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
+ * 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 "csp.h"
+#include "frame.h"
+#include "mastering_display_metadata.h"
+#include "pixfmt.h"
+
+/*
+ * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html
+ * The older ones (bt470bg/m) are also explained in their respective ITU docs
+ * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf)
+ * whereas the newer ones can typically be copied directly from wikipedia :)
+ */
+static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
+    [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
+    [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
+    [AVCOL_SPC_SMPTE170M]  = { 0.299,  0.587,  0.114  },
+    [AVCOL_SPC_BT709]      = { 0.2126, 0.7152, 0.0722 },
+    [AVCOL_SPC_SMPTE240M]  = { 0.212,  0.701,  0.087  },
+    [AVCOL_SPC_YCOCG]      = { 0.25,   0.5,    0.25   },
+    [AVCOL_SPC_RGB]        = { 1,      1,      1      },
+    [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 },
+    [AVCOL_SPC_BT2020_CL]  = { 0.2627, 0.6780, 0.0593 },
+};
+
+const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp)
+{
+    const struct LumaCoefficients *coeffs;
+
+    if (csp >= AVCOL_SPC_NB)
+        return NULL;
+    coeffs = &luma_coefficients[csp];
+    if (!coeffs->cr)
+        return NULL;
+
+    return coeffs;
+}
+
+#define WP_D65 { 0.3127, 0.3290 }
+#define WP_C   { 0.3100, 0.3160 }
+#define WP_DCI { 0.3140, 0.3510 }
+#define WP_E   { 1/3.0f, 1/3.0f }
+
+static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = {
+    [AVCOL_PRI_BT709]     = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } },
+    [AVCOL_PRI_BT470M]    = { WP_C,   { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } },
+    [AVCOL_PRI_BT470BG]   = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } },
+    [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
+    [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } },
+    [AVCOL_PRI_SMPTE428]  = { WP_E,   { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } },
+    [AVCOL_PRI_SMPTE431]  = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
+    [AVCOL_PRI_SMPTE432]  = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } },
+    [AVCOL_PRI_FILM]      = { WP_C,   { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } },
+    [AVCOL_PRI_BT2020]    = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } },
+    [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } },
+};
+
+const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm)
+{
+    const struct ColorPrimaries *p;
+
+    if (prm >= AVCOL_PRI_NB)
+        return NULL;
+    p = &color_primaries[prm];
+    if (!p->prim.xr)
+        return NULL;
+
+    return p;
+}
+
+enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm)
+{
+    double delta;
+
+    for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) {
+        const struct ColorPrimaries *ref = &color_primaries[p];
+        if (!ref->prim.xr)
+            continue;
+
+        delta = fabs(prm->prim.xr - ref->prim.xr) +
+                fabs(prm->prim.yr - ref->prim.yr) +
+                fabs(prm->prim.yg - ref->prim.yg) +
+                fabs(prm->prim.yg - ref->prim.yg) +
+                fabs(prm->prim.yb - ref->prim.yb) +
+                fabs(prm->prim.yb - ref->prim.yb) +
+                fabs(prm->wp.xw - ref->wp.xw) +
+                fabs(prm->wp.yw - ref->wp.yw);
+
+        if (delta < 0.001)
+            return p;
+    }
+
+    return AVCOL_PRI_UNSPECIFIED;
+}
diff --git a/libavutil/csp.h b/libavutil/csp.h
new file mode 100644
index 0000000000..1bcde7ddd3
--- /dev/null
+++ b/libavutil/csp.h
@@ -0,0 +1,49 @@ 
+/*
+ * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
+ * 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
+ */
+
+#ifndef AVUTIL_CSP_H
+#define AVUTIL_CSP_H
+
+#include "libavutil/frame.h"
+#include "libavutil/pixfmt.h"
+
+struct LumaCoefficients {
+    double cr, cg, cb;
+};
+
+struct PrimaryCoefficients {
+    double xr, yr, xg, yg, xb, yb;
+};
+
+struct WhitepointCoefficients {
+    double xw, yw;
+};
+
+struct ColorPrimaries {
+    struct WhitepointCoefficients wp;
+    struct PrimaryCoefficients prim;
+};
+
+/* Returns AVCOL_PRI_UNSPECIFIED if no clear match can be identified */
+enum AVColorPrimaries av_detect_color_primaries(const struct ColorPrimaries *prm);
+
+const struct ColorPrimaries *av_get_color_primaries(enum AVColorPrimaries prm);
+const struct LumaCoefficients *av_get_luma_coefficients(enum AVColorSpace csp);
+
+#endif /* AVUTIL_CSP_H */