On 03/26/2013 06:21 PM, Nicolas Bertrand wrote: > Used to test XYZ JPEG2000 output > before his introduction in avscale? > --- > libavfilter/Makefile | 1 + > libavfilter/allfilters.c | 1 + > libavfilter/version.h | 2 +- > libavfilter/vf_xyz2rgb.c | 250 > ++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 253 insertions(+), 1 deletion(-) > create mode 100644 libavfilter/vf_xyz2rgb.c > > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 4a3331a..748141d 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -55,6 +55,7 @@ OBJS-$(CONFIG_FPS_FILTER) += vf_fps.o > OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o > OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o > OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o > +OBJS-$(CONFIG_XYZ2RGB_FILTER) += vf_xyz2rgb.o
alphabetical order please > OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o > OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o > OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index f3ce91c..8c98abb 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -99,6 +99,7 @@ void avfilter_register_all(void) > REGISTER_FILTER(VFLIP, vflip, vf); > REGISTER_FILTER(YADIF, yadif, vf); > > + REGISTER_FILTER(XYZ2RGB, xyz2rgb, vf); > REGISTER_FILTER(COLOR, color, vsrc); > REGISTER_FILTER(FREI0R, frei0r_src, vsrc); > REGISTER_FILTER(MOVIE, movie, vsrc); group with the 'vf' not the 'vsrc' and in alphabetical order. > diff --git a/libavfilter/version.h b/libavfilter/version.h > index a07af2b..1a5ec42 100644 > --- a/libavfilter/version.h > +++ b/libavfilter/version.h > @@ -29,7 +29,7 @@ > #include "libavutil/avutil.h" > > #define LIBAVFILTER_VERSION_MAJOR 3 > -#define LIBAVFILTER_VERSION_MINOR 5 > +#define LIBAVFILTER_VERSION_MINOR 6 > #define LIBAVFILTER_VERSION_MICRO 0 > > #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ > diff --git a/libavfilter/vf_xyz2rgb.c b/libavfilter/vf_xyz2rgb.c > new file mode 100644 > index 0000000..13d2b5e > --- /dev/null > +++ b/libavfilter/vf_xyz2rgb.c > @@ -0,0 +1,250 @@ > +/* > + * XYZ to RGB filter > + * Copyright (c) 2012 Matthias Buercher > + * Copyright (c) 2013 Nicolas Bertrand <[email protected]> > + * > + * This file is part of Libav. > + * > + * Libav 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. > + * > + * Libav 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 Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +/** > + * @file > + * xyz2rgb filter > + * Converts from XYZ to RGB space > + * Useful to convert jpeg2000 files from MXF containers in DCP > + * The filter has no parameters > + */ > + > +#include <string.h> > + > +#include "avfilter.h" > +#include "formats.h" > +#include "internal.h" > +#include "video.h" > +#include "libavutil/pixdesc.h" > +#include "libavutil/internal.h" > +#include "libavutil/intreadwrite.h" > +#include "libavutil/imgutils.h" nit: put the libavutil includes before the libavfilter includes > + > +typedef struct { > + int xyzgamma[4096]; > + int rgbgamma[4096]; > + int matrix[3][3]; > +} XYZ2RGBContext; > + > +static int query_formats(AVFilterContext * ctx) > +{ > + AVFilterFormats *formats; > + int ret = -1 ; > + > + if (ctx->inputs[0]) { > + formats = NULL; > + ret = ff_add_format(&formats, AV_PIX_FMT_XYZ12); > + ff_formats_ref(formats, &ctx->inputs[0]->out_formats); > + } > + if (ctx->outputs[0]) { > + formats = NULL; > + ret = ff_add_format(&formats, AV_PIX_FMT_RGB48); > + ff_formats_ref(formats, &ctx->outputs[0]->in_formats); > + } > + return ret; > +} > + > +/** > + * The gamma values is precalculated in an array _are_ precalculated > + * XYZ uses projector gamma 2.6 > + * sRGB uses gamma 2.2 > + * The gamma function is the inverse power function, calculated in [0..1] > and scaled to 12 bitdepth [0.4095] > + * 0.5 is added for rounding you can just say that it is calculated in 12-bit fixed-point > + * > + * The matrix multipliers are precalculated and scaled to 12bit bitdepth > (4096 values) > + * For documentation see > + * http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html > + * http://en.wikipedia.org/wiki/SRGB > +*/ > + > +static int config_props(AVFilterLink * inlink) > +{ > + XYZ2RGBContext *settings = inlink->dst->priv; > + int i; > + double xyzgamma = 2.6; > + double rgbgamma = 1.0 / 2.2; > + > + for (i = 0; i < 4096; i++) { > + settings->xyzgamma[i] = > + (int) (pow(i / 4095.0, xyzgamma) * 4095.0 + 0.5); > + settings->rgbgamma[i] = > + (int) (pow(i / 4095.0, rgbgamma) * 4095.0 + 0.5); > + } > + > + settings->matrix[0][0] = (int) (3.2404542 * 4095.0 + 0.5); > + settings->matrix[0][1] = (int) (-1.5371385 * 4095.0 - 0.5); > + settings->matrix[0][2] = (int) (-0.4985314 * 4095.0 - 0.5); > + settings->matrix[1][0] = (int) (-0.9692660 * 4095.0 - 0.5); > + settings->matrix[1][1] = (int) (1.8760108 * 4095.0 + 0.5); > + settings->matrix[1][2] = (int) (0.0415560 * 4095.0 + 0.5); > + settings->matrix[2][0] = (int) (0.0556434 * 4095.0 + 0.5); > + settings->matrix[2][1] = (int) (-0.2040259 * 4095.0 - 0.5); > + settings->matrix[2][2] = (int) (1.0572252 * 4095.0 + 0.5); > + return 0; > +} I would prefer that the matrix values be hardcoded in a static table, with the decimal values in the comments. > + > +static int filter_frame(AVFilterLink * inlink, AVFrame * in) > +{ > + AVFilterLink *outlink = inlink->dst->outputs[0]; > + XYZ2RGBContext *settings = inlink->dst->priv; > + > + AVFrame *out; > + uint8_t *inrow, *outrow; > + int i, j; > + int r, g, b, x, y, z; > + > + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); > + if (!out) { > + av_frame_free(&in); > + return AVERROR(ENOMEM); > + } > + > + out->pts = in->pts; > + inrow = in->data[0]; > + outrow = out->data[0]; > + > + /* > + * The calculation is separated on input-format RB24 or RGB48LE isn't RGB the output format? > + * In both cases the XYZ-values are scaled to 12bit bitdepth, > + * then transformed to sRGB and and scaled back to the original bitdepth > + */ > + for (i = 0; i < inlink->h; i++) { > + if (inlink->format == AV_PIX_FMT_RGB24) { and shouldn't that be outlink->format? > + for (j = 0; j < inlink->w * 3; j += 3) { > + > + // scale from 8bit to 12bit > + x = inrow[j] << 4; > + y = inrow[j + 1] << 4; > + z = inrow[j + 2] << 4; isn't the XYZ input data 12-bit not 8-bit? > + > + // convert from XYZ to XYZlinear > + x = settings->xyzgamma[x]; > + y = settings->xyzgamma[y]; > + z = settings->xyzgamma[z]; > + > + // convert from XYZlinear to sRGBlinear > + r = settings->matrix[0][0] * x + > + settings->matrix[0][1] * y + > + settings->matrix[0][2] * z >> 12; > + g = settings->matrix[1][0] * x + > + settings->matrix[1][1] * y + > + settings->matrix[1][2] * z >> 12; > + b = settings->matrix[2][0] * x + > + settings->matrix[1][2] * y + > + settings->matrix[2][2] * z >> 12; > + > + // limit values to 12bit legal values [0..0495] > + if (r > 4095) > + r = 4095; > + if (r < 0) > + r = 0; > + if (g > 4095) > + g = 4095; > + if (g < 0) > + g = 0; > + if (b > 4095) > + b = 4095; > + if (b < 0) > + b = 0; > + > + // convert from sRGBlinear to RGB and scale from 12bit to > 8bit > + r = settings->rgbgamma[r] >> 4; // /16 12bit->8bit > + g = settings->rgbgamma[g] >> 4; > + b = settings->rgbgamma[b] >> 4; > + > + outrow[j] = (uint8_t) r; > + outrow[j + 1] = (uint8_t) g; > + outrow[j + 2] = (uint8_t) b; > + } > + } else { // 16bits case so XYZ input format > + for (j = 0; j < inlink->w * 6; j += 6) { > + // read low endian and scale from 16bit to 12bit > + x = (inrow[j] + (inrow[j + 1] << 8)) >> 4; > + y = (inrow[j + 2] + (inrow[j + 3] << 8)) >> 4; > + z = (inrow[j + 4] + (inrow[j + 5] << 8)) >> 4; same here... > + // convert from XYZ to XYZlinear > + x = settings->xyzgamma[x]; > + y = settings->xyzgamma[y]; > + z = settings->xyzgamma[z]; > + > + // convert from XYZlinear to sRGBlinear > + r = settings->matrix[0][0] * x + > + settings->matrix[0][1] * y + > + settings->matrix[0][2] * z >> 12; > + g = settings->matrix[1][0] * x + > + settings->matrix[1][1] * y + > + settings->matrix[1][2] * z >> 12; > + b = settings->matrix[2][0] * x + > + settings->matrix[1][2] * y + > + settings->matrix[2][2] * z >> 12; > + > + // limit values to 12bit legal values [0..0495] > + if (r > 4095) > + r = 4095; > + if (r < 0) > + r = 0; > + if (g > 4095) > + g = 4095; > + if (g < 0) > + g = 0; > + if (b > 4095) > + b = 4095; > + if (b < 0) > + b = 0; av_clip_uintp2(r, 12); > + > + // convert from sRGBlinear to RGB and scale from 12bit to > 16bit > + r = settings->rgbgamma[r] << 4; > + g = settings->rgbgamma[g] << 4; > + b = settings->rgbgamma[b] << 4; > + > + // write low endian little-endian > + outrow[j] = (uint8_t) (r & 255); > + outrow[j + 1] = (uint8_t) (r >> 8); > + outrow[j + 2] = (uint8_t) (g & 255); > + outrow[j + 3] = (uint8_t) (g >> 8); > + outrow[j + 4] = (uint8_t) (b & 255); > + outrow[j + 5] = (uint8_t) (b >> 8); libavutil has shortcuts for that see libavutil/intreadwrite.h > + } > + } > + inrow += in->linesize[0]; > + outrow += out->linesize[0]; > + } > + av_frame_free(&in); > + return ff_filter_frame(outlink, out); > +} > + > +AVFilter avfilter_vf_xyz2rgb = { > + .name = "xyz2rgb", > + .description = NULL_IF_CONFIG_SMALL("Converts XYZ to RGB."), > + .priv_size = sizeof(XYZ2RGBContext), > + .query_formats = query_formats, > + .inputs = (const AVFilterPad[]) {{.name = "default", > + .type = AVMEDIA_TYPE_VIDEO, > + .filter_frame = filter_frame, > + .config_props = config_props, > + .min_perms = AV_PERM_READ,}, > + {.name = NULL}}, > + .outputs = (const AVFilterPad[]) {{.name = "default", > + .type = AVMEDIA_TYPE_VIDEO,}, > + {.name = NULL}}, > +}; Thanks! -Justin _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
