From: "Xiang, Haihao" <haihao.xiang-at-intel.com@ffmpeg.org> To: "ffmpeg-devel@ffmpeg.org" <ffmpeg-devel@ffmpeg.org> Cc: "cyfdecyf@gmail.com" <cyfdecyf@gmail.com> Subject: Re: [FFmpeg-devel] [PATCH 1/2] avfilter/vf_lut3d: expose 3D LUT file parse function. Date: Mon, 16 Oct 2023 07:51:50 +0000 Message-ID: <d3bfd7be73b3ee405c00ab3084ac55a63e8a48c9.camel@intel.com> (raw) In-Reply-To: <20230923154125.31376-2-cyfdecyf@gmail.com> On Sa, 2023-09-23 at 23:36 +0800, Chen Yufei wrote: > Signed-off-by: Chen Yufei <cyfdecyf@gmail.com> > --- > libavfilter/Makefile | 8 +- > libavfilter/lut3d.c | 669 +++++++++++++++++++++++++++++++++++++++++ > libavfilter/lut3d.h | 13 + > libavfilter/vf_lut3d.c | 590 +----------------------------------- > 4 files changed, 689 insertions(+), 591 deletions(-) > create mode 100644 libavfilter/lut3d.c > > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 2fe0033b21..c1cd797e5c 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -330,7 +330,7 @@ OBJS-$(CONFIG_GRAPHMONITOR_FILTER) += > f_graphmonitor.o > OBJS-$(CONFIG_GRAYWORLD_FILTER) += vf_grayworld.o > OBJS-$(CONFIG_GREYEDGE_FILTER) += vf_colorconstancy.o > OBJS-$(CONFIG_GUIDED_FILTER) += vf_guided.o > -OBJS-$(CONFIG_HALDCLUT_FILTER) += vf_lut3d.o framesync.o > +OBJS-$(CONFIG_HALDCLUT_FILTER) += vf_lut3d.o lut3d.o > framesync.o > OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o > OBJS-$(CONFIG_HFLIP_VULKAN_FILTER) += vf_flip_vulkan.o vulkan.o > OBJS-$(CONFIG_HISTEQ_FILTER) += vf_histeq.o > @@ -367,10 +367,10 @@ OBJS-$(CONFIG_LIMITDIFF_FILTER) += > vf_limitdiff.o framesync.o > OBJS-$(CONFIG_LIMITER_FILTER) += vf_limiter.o > OBJS-$(CONFIG_LOOP_FILTER) += f_loop.o > OBJS-$(CONFIG_LUMAKEY_FILTER) += vf_lumakey.o > -OBJS-$(CONFIG_LUT1D_FILTER) += vf_lut3d.o > +OBJS-$(CONFIG_LUT1D_FILTER) += vf_lut3d.o lut3d.o > OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o > OBJS-$(CONFIG_LUT2_FILTER) += vf_lut2.o framesync.o > -OBJS-$(CONFIG_LUT3D_FILTER) += vf_lut3d.o framesync.o > +OBJS-$(CONFIG_LUT3D_FILTER) += vf_lut3d.o lut3d.o > framesync.o > OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o > OBJS-$(CONFIG_LUTYUV_FILTER) += vf_lut.o > OBJS-$(CONFIG_MASKEDCLAMP_FILTER) += vf_maskedclamp.o framesync.o > @@ -549,7 +549,7 @@ OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += > vidstabutils.o vf_vidstabtransfo > OBJS-$(CONFIG_VIF_FILTER) += vf_vif.o framesync.o > OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o > OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o > -OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o > +OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o lut3d.o This should be moved to patch 2/2. Thanks Haihao > OBJS-$(CONFIG_VSTACK_FILTER) += vf_stack.o framesync.o > OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o > OBJS-$(CONFIG_WAVEFORM_FILTER) += vf_waveform.o > diff --git a/libavfilter/lut3d.c b/libavfilter/lut3d.c > new file mode 100644 > index 0000000000..173979adcc > --- /dev/null > +++ b/libavfilter/lut3d.c > @@ -0,0 +1,669 @@ > +/* > + * Copyright (c) 2013 Clément Bœsch > + * Copyright (c) 2018 Paul B Mahol > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include "lut3d.h" > + > +#include <float.h> > + > +#include "libavutil/avstring.h" > +#include "libavutil/file_open.h" > + > +#define EXPONENT_MASK 0x7F800000 > +#define MANTISSA_MASK 0x007FFFFF > +#define SIGN_MASK 0x80000000 > + > +static inline float sanitizef(float f) > +{ > + union av_intfloat32 t; > + t.f = f; > + > + if ((t.i & EXPONENT_MASK) == EXPONENT_MASK) { > + if ((t.i & MANTISSA_MASK) != 0) { > + // NAN > + return 0.0f; > + } else if (t.i & SIGN_MASK) { > + // -INF > + return -FLT_MAX; > + } else { > + // +INF > + return FLT_MAX; > + } > + } > + return f; > +} > + > +static inline float lerpf(float v0, float v1, float f) > +{ > + return v0 + (v1 - v0) * f; > +} > + > +static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec > *v1, float f) > +{ > + struct rgbvec v = { > + lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, > f) > + }; > + return v; > +} > + > +int ff_allocate_3dlut(AVFilterContext *ctx, LUT3DContext *lut3d, int lutsize, > int prelut) > +{ > + int i; > + if (lutsize < 2 || lutsize > MAX_LEVEL) { > + av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n"); > + return AVERROR(EINVAL); > + } > + > + av_freep(&lut3d->lut); > + lut3d->lut = av_malloc_array(lutsize * lutsize * lutsize, sizeof(*lut3d- > >lut)); > + if (!lut3d->lut) > + return AVERROR(ENOMEM); > + > + if (prelut) { > + lut3d->prelut.size = PRELUT_SIZE; > + for (i = 0; i < 3; i++) { > + av_freep(&lut3d->prelut.lut[i]); > + lut3d->prelut.lut[i] = av_malloc_array(PRELUT_SIZE, > sizeof(*lut3d->prelut.lut[0])); > + if (!lut3d->prelut.lut[i]) > + return AVERROR(ENOMEM); > + } > + } else { > + lut3d->prelut.size = 0; > + for (i = 0; i < 3; i++) { > + av_freep(&lut3d->prelut.lut[i]); > + } > + } > + lut3d->lutsize = lutsize; > + lut3d->lutsize2 = lutsize * lutsize; > + return 0; > +} > + > +static int set_identity_matrix(AVFilterContext *ctx, LUT3DContext *lut3d, int > size) > +{ > + int ret, i, j, k; > + const int size2 = size * size; > + const float c = 1. / (size - 1); > + > + ret = ff_allocate_3dlut(ctx, lut3d, size, 0); > + if (ret < 0) > + return ret; > + > + for (k = 0; k < size; k++) { > + for (j = 0; j < size; j++) { > + for (i = 0; i < size; i++) { > + struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > + vec->r = k * c; > + vec->g = j * c; > + vec->b = i * c; > + } > + } > + } > + > + return 0; > +} > + > +#define MAX_LINE_SIZE 512 > + > +static int skip_line(const char *p) > +{ > + while (*p && av_isspace(*p)) > + p++; > + return !*p || *p == '#'; > +} > + > +static char* fget_next_word(char* dst, int max, FILE* f) > +{ > + int c; > + char *p = dst; > + > + /* for null */ > + max--; > + /* skip until next non whitespace char */ > + while ((c = fgetc(f)) != EOF) { > + if (av_isspace(c)) > + continue; > + > + *p++ = c; > + max--; > + break; > + } > + > + /* get max bytes or up until next whitespace char */ > + for (; max > 0; max--) { > + if ((c = fgetc(f)) == EOF) > + break; > + > + if (av_isspace(c)) > + break; > + > + *p++ = c; > + } > + > + *p = 0; > + if (p == dst) > + return NULL; > + return p; > +} > + > + > +#define NEXT_LINE(loop_cond) do { \ > + if (!fgets(line, sizeof(line), f)) { \ > + av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \ > + return AVERROR_INVALIDDATA; \ > + } \ > +} while (loop_cond) > + > +#define NEXT_LINE_OR_GOTO(loop_cond, label) do { \ > + if (!fgets(line, sizeof(line), f)) { \ > + av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \ > + ret = AVERROR_INVALIDDATA; \ > + goto label; \ > + } \ > +} while (loop_cond) > + > +/* Basically r g and b float values on each line, with a facultative > 3DLUTSIZE > + * directive; seems to be generated by Davinci */ > +static int parse_dat(AVFilterContext *ctx, LUT3DContext *lut3d, FILE *f) > +{ > + char line[MAX_LINE_SIZE]; > + int ret, i, j, k, size, size2; > + > + lut3d->lutsize = size = 33; > + size2 = size * size; > + > + NEXT_LINE(skip_line(line)); > + if (!strncmp(line, "3DLUTSIZE ", 10)) { > + size = strtol(line + 10, NULL, 0); > + > + NEXT_LINE(skip_line(line)); > + } > + > + ret = ff_allocate_3dlut(ctx, lut3d, size, 0); > + if (ret < 0) > + return ret; > + > + for (k = 0; k < size; k++) { > + for (j = 0; j < size; j++) { > + for (i = 0; i < size; i++) { > + struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > + if (k != 0 || j != 0 || i != 0) > + NEXT_LINE(skip_line(line)); > + if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != > 3) > + return AVERROR_INVALIDDATA; > + } > + } > + } > + return 0; > +} > + > +/* Iridas format */ > +static int parse_cube(AVFilterContext *ctx, LUT3DContext *lut3d, FILE *f) > +{ > + char line[MAX_LINE_SIZE]; > + float min[3] = {0.0, 0.0, 0.0}; > + float max[3] = {1.0, 1.0, 1.0}; > + > + while (fgets(line, sizeof(line), f)) { > + if (!strncmp(line, "LUT_3D_SIZE", 11)) { > + int ret, i, j, k; > + const int size = strtol(line + 12, NULL, 0); > + const int size2 = size * size; > + > + ret = ff_allocate_3dlut(ctx, lut3d, size, 0); > + if (ret < 0) > + return ret; > + > + for (k = 0; k < size; k++) { > + for (j = 0; j < size; j++) { > + for (i = 0; i < size; i++) { > + struct rgbvec *vec = &lut3d->lut[i * size2 + j * size > + k]; > + > + do { > +try_again: > + NEXT_LINE(0); > + if (!strncmp(line, "DOMAIN_", 7)) { > + float *vals = NULL; > + if (!strncmp(line + 7, "MIN ", 4)) vals > = min; > + else if (!strncmp(line + 7, "MAX ", 4)) vals > = max; > + if (!vals) > + return AVERROR_INVALIDDATA; > + av_sscanf(line + 11, "%f %f %f", vals, vals + > 1, vals + 2); > + av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | > max: %f %f %f\n", > + min[0], min[1], min[2], max[0], > max[1], max[2]); > + goto try_again; > + } else if (!strncmp(line, "TITLE", 5)) { > + goto try_again; > + } > + } while (skip_line(line)); > + if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, > &vec->b) != 3) > + return AVERROR_INVALIDDATA; > + } > + } > + } > + break; > + } > + } > + > + lut3d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f); > + lut3d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f); > + lut3d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f); > + > + return 0; > +} > + > +/* Assume 17x17x17 LUT with a 16-bit depth > + * FIXME: it seems there are various 3dl formats */ > +static int parse_3dl(AVFilterContext *ctx, LUT3DContext *lut3d, FILE *f) > +{ > + char line[MAX_LINE_SIZE]; > + int ret, i, j, k; > + const int size = 17; > + const int size2 = 17 * 17; > + const float scale = 16*16*16; > + > + lut3d->lutsize = size; > + > + ret = ff_allocate_3dlut(ctx, lut3d, size, 0); > + if (ret < 0) > + return ret; > + > + NEXT_LINE(skip_line(line)); > + for (k = 0; k < size; k++) { > + for (j = 0; j < size; j++) { > + for (i = 0; i < size; i++) { > + int r, g, b; > + struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > + > + NEXT_LINE(skip_line(line)); > + if (av_sscanf(line, "%d %d %d", &r, &g, &b) != 3) > + return AVERROR_INVALIDDATA; > + vec->r = r / scale; > + vec->g = g / scale; > + vec->b = b / scale; > + } > + } > + } > + return 0; > +} > + > +/* Pandora format */ > +static int parse_m3d(AVFilterContext *ctx, LUT3DContext *lut3d, FILE *f) > +{ > + float scale; > + int ret, i, j, k, size, size2, in = -1, out = -1; > + char line[MAX_LINE_SIZE]; > + uint8_t rgb_map[3] = {0, 1, 2}; > + > + while (fgets(line, sizeof(line), f)) { > + if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0); > + else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0); > + else if (!strncmp(line, "values", 6)) { > + const char *p = line + 6; > +#define SET_COLOR(id) do { \ > + while (av_isspace(*p)) \ > + p++; \ > + switch (*p) { \ > + case 'r': rgb_map[id] = 0; break; \ > + case 'g': rgb_map[id] = 1; break; \ > + case 'b': rgb_map[id] = 2; break; \ > + } \ > + while (*p && !av_isspace(*p)) \ > + p++; \ > +} while (0) > + SET_COLOR(0); > + SET_COLOR(1); > + SET_COLOR(2); > + break; > + } > + } > + > + if (in == -1 || out == -1) { > + av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n"); > + return AVERROR_INVALIDDATA; > + } > + if (in < 2 || out < 2 || > + in > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL || > + out > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL) { > + av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out); > + return AVERROR_INVALIDDATA; > + } > + for (size = 1; size*size*size < in; size++); > + lut3d->lutsize = size; > + size2 = size * size; > + > + ret = ff_allocate_3dlut(ctx, lut3d, size, 0); > + if (ret < 0) > + return ret; > + > + scale = 1. / (out - 1); > + > + for (k = 0; k < size; k++) { > + for (j = 0; j < size; j++) { > + for (i = 0; i < size; i++) { > + struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > + float val[3]; > + > + NEXT_LINE(0); > + if (av_sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3) > + return AVERROR_INVALIDDATA; > + vec->r = val[rgb_map[0]] * scale; > + vec->g = val[rgb_map[1]] * scale; > + vec->b = val[rgb_map[2]] * scale; > + } > + } > + } > + return 0; > +} > + > +static int nearest_sample_index(float *data, float x, int low, int hi) > +{ > + int mid; > + if (x < data[low]) > + return low; > + > + if (x > data[hi]) > + return hi; > + > + for (;;) { > + av_assert0(x >= data[low]); > + av_assert0(x <= data[hi]); > + av_assert0((hi-low) > 0); > + > + if (hi - low == 1) > + return low; > + > + mid = (low + hi) / 2; > + > + if (x < data[mid]) > + hi = mid; > + else > + low = mid; > + } > + > + return 0; > +} > + > +#define NEXT_FLOAT_OR_GOTO(value, label) \ > + if (!fget_next_word(line, sizeof(line) ,f)) { \ > + ret = AVERROR_INVALIDDATA; \ > + goto label; \ > + } \ > + if (av_sscanf(line, "%f", &value) != 1) { \ > + ret = AVERROR_INVALIDDATA; \ > + goto label; \ > + } > + > +static int parse_cinespace(AVFilterContext *ctx, LUT3DContext *lut3d, FILE > *f) > +{ > + char line[MAX_LINE_SIZE]; > + float in_min[3] = {0.0, 0.0, 0.0}; > + float in_max[3] = {1.0, 1.0, 1.0}; > + float out_min[3] = {0.0, 0.0, 0.0}; > + float out_max[3] = {1.0, 1.0, 1.0}; > + int inside_metadata = 0, size, size2; > + int prelut = 0; > + int ret = 0; > + > + int prelut_sizes[3] = {0, 0, 0}; > + float *in_prelut[3] = {NULL, NULL, NULL}; > + float *out_prelut[3] = {NULL, NULL, NULL}; > + > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + if (strncmp(line, "CSPLUTV100", 10)) { > + av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n"); > + ret = AVERROR(EINVAL); > + goto end; > + } > + > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + if (strncmp(line, "3D", 2)) { > + av_log(ctx, AV_LOG_ERROR, "Not 3D LUT format\n"); > + ret = AVERROR(EINVAL); > + goto end; > + } > + > + while (1) { > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + > + if (!strncmp(line, "BEGIN METADATA", 14)) { > + inside_metadata = 1; > + continue; > + } > + if (!strncmp(line, "END METADATA", 12)) { > + inside_metadata = 0; > + continue; > + } > + if (inside_metadata == 0) { > + int size_r, size_g, size_b; > + > + for (int i = 0; i < 3; i++) { > + int npoints = strtol(line, NULL, 0); > + > + if (npoints > 2) { > + float v,last; > + > + if (npoints > PRELUT_SIZE) { > + av_log(ctx, AV_LOG_ERROR, "Prelut size too > large.\n"); > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + if (in_prelut[i] || out_prelut[i]) { > + av_log(ctx, AV_LOG_ERROR, "Invalid file has multiple > preluts.\n"); > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + in_prelut[i] = (float*)av_malloc(npoints * > sizeof(float)); > + out_prelut[i] = (float*)av_malloc(npoints * > sizeof(float)); > + if (!in_prelut[i] || !out_prelut[i]) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > + prelut_sizes[i] = npoints; > + in_min[i] = FLT_MAX; > + in_max[i] = -FLT_MAX; > + out_min[i] = FLT_MAX; > + out_max[i] = -FLT_MAX; > + > + for (int j = 0; j < npoints; j++) { > + NEXT_FLOAT_OR_GOTO(v, end) > + in_min[i] = FFMIN(in_min[i], v); > + in_max[i] = FFMAX(in_max[i], v); > + in_prelut[i][j] = v; > + if (j > 0 && v < last) { > + av_log(ctx, AV_LOG_ERROR, "Invalid file, non > increasing prelut.\n"); > + ret = AVERROR(ENOMEM); > + goto end; > + } > + last = v; > + } > + > + for (int j = 0; j < npoints; j++) { > + NEXT_FLOAT_OR_GOTO(v, end) > + out_min[i] = FFMIN(out_min[i], v); > + out_max[i] = FFMAX(out_max[i], v); > + out_prelut[i][j] = v; > + } > + > + } else if (npoints == 2) { > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != > 2) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != > 2) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + } else { > + av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut > points.\n"); > + ret = AVERROR_PATCHWELCOME; > + goto end; > + } > + > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + } > + > + if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3) > { > + ret = AVERROR(EINVAL); > + goto end; > + } > + if (size_r != size_g || size_r != size_b) { > + av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: > %dx%dx%d.\n", size_r, size_g, size_b); > + ret = AVERROR_PATCHWELCOME; > + goto end; > + } > + > + size = size_r; > + size2 = size * size; > + > + if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2]) > + prelut = 1; > + > + ret = ff_allocate_3dlut(ctx, lut3d, size, prelut); > + if (ret < 0) > + return ret; > + > + for (int k = 0; k < size; k++) { > + for (int j = 0; j < size; j++) { > + for (int i = 0; i < size; i++) { > + struct rgbvec *vec = &lut3d->lut[i * size2 + j * size > + k]; > + > + NEXT_LINE_OR_GOTO(skip_line(line), end); > + if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, > &vec->b) != 3) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + vec->r *= out_max[0] - out_min[0]; > + vec->g *= out_max[1] - out_min[1]; > + vec->b *= out_max[2] - out_min[2]; > + } > + } > + } > + > + break; > + } > + } > + > + if (prelut) { > + for (int c = 0; c < 3; c++) { > + > + lut3d->prelut.min[c] = in_min[c]; > + lut3d->prelut.max[c] = in_max[c]; > + lut3d->prelut.scale[c] = (1.0f / (float)(in_max[c] - in_min[c])) > * (lut3d->prelut.size - 1); > + > + for (int i = 0; i < lut3d->prelut.size; ++i) { > + float mix = (float) i / (float)(lut3d->prelut.size - 1); > + float x = lerpf(in_min[c], in_max[c], mix), a, b; > + > + int idx = nearest_sample_index(in_prelut[c], x, 0, > prelut_sizes[c]-1); > + av_assert0(idx + 1 < prelut_sizes[c]); > + > + a = out_prelut[c][idx + 0]; > + b = out_prelut[c][idx + 1]; > + mix = x - in_prelut[c][idx]; > + > + lut3d->prelut.lut[c][i] = sanitizef(lerpf(a, b, mix)); > + } > + } > + lut3d->scale.r = 1.00f; > + lut3d->scale.g = 1.00f; > + lut3d->scale.b = 1.00f; > + > + } else { > + lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f); > + lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f); > + lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f); > + } > + > +end: > + for (int c = 0; c < 3; c++) { > + av_freep(&in_prelut[c]); > + av_freep(&out_prelut[c]); > + } > + return ret; > +} > + > +av_cold int ff_lut3d_init(AVFilterContext *ctx, LUT3DContext *lut3d) > +{ > + int ret; > + FILE *f; > + const char *ext; > + > + lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f; > + > + if (!lut3d->file) { > + return set_identity_matrix(ctx, lut3d, 32); > + } > + > + f = avpriv_fopen_utf8(lut3d->file, "r"); > + if (!f) { > + ret = AVERROR(errno); > + av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret)); > + return ret; > + } > + > + ext = strrchr(lut3d->file, '.'); > + if (!ext) { > + av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the > extension\n"); > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + ext++; > + > + if (!av_strcasecmp(ext, "dat")) { > + ret = parse_dat(ctx, lut3d, f); > + } else if (!av_strcasecmp(ext, "3dl")) { > + ret = parse_3dl(ctx, lut3d, f); > + } else if (!av_strcasecmp(ext, "cube")) { > + ret = parse_cube(ctx, lut3d, f); > + } else if (!av_strcasecmp(ext, "m3d")) { > + ret = parse_m3d(ctx, lut3d, f); > + } else if (!av_strcasecmp(ext, "csp")) { > + ret = parse_cinespace(ctx, lut3d, f); > + } else { > + av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext); > + ret = AVERROR(EINVAL); > + } > + > + if (!ret && !lut3d->lutsize) { > + av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n"); > + ret = AVERROR_INVALIDDATA; > + } > + > +end: > + fclose(f); > + return ret; > +} > + > +av_cold void ff_lut3d_uninit(LUT3DContext *lut3d) > +{ > + int i; > + av_freep(&lut3d->lut); > + > + for (i = 0; i < 3; i++) { > + av_freep(&lut3d->prelut.lut[i]); > + } > +} > diff --git a/libavfilter/lut3d.h b/libavfilter/lut3d.h > index 14e3c7fea6..b6aaed85f1 100644 > --- a/libavfilter/lut3d.h > +++ b/libavfilter/lut3d.h > @@ -84,4 +84,17 @@ typedef struct ThreadData { > > void ff_lut3d_init_x86(LUT3DContext *s, const AVPixFmtDescriptor *desc); > > +int ff_allocate_3dlut(AVFilterContext *ctx, LUT3DContext *lut3d, int lutsize, > int prelut); > + > +/** > + * Load 3D LUT from file. > + * > + * @param lut3d LUT3DContext Load 3D LUT from path specified by `lut3d- > >file`. > + * If `lut3d->file` is NULL, initialize an identity 3D LUT. > + */ > +int ff_lut3d_init(AVFilterContext *ctx, LUT3DContext *lut3d); > + > +/** Release memory used to hold 3D LUT. */ > +void ff_lut3d_uninit(LUT3DContext *lut3d); > + > #endif /* AVFILTER_LUT3D_H */ > diff --git a/libavfilter/vf_lut3d.c b/libavfilter/vf_lut3d.c > index 4edcc2c7a7..1da798e210 100644 > --- a/libavfilter/vf_lut3d.c > +++ b/libavfilter/vf_lut3d.c > @@ -552,39 +552,6 @@ static int skip_line(const char *p) > return !*p || *p == '#'; > } > > -static char* fget_next_word(char* dst, int max, FILE* f) > -{ > - int c; > - char *p = dst; > - > - /* for null */ > - max--; > - /* skip until next non whitespace char */ > - while ((c = fgetc(f)) != EOF) { > - if (av_isspace(c)) > - continue; > - > - *p++ = c; > - max--; > - break; > - } > - > - /* get max bytes or up until next whitespace char */ > - for (; max > 0; max--) { > - if ((c = fgetc(f)) == EOF) > - break; > - > - if (av_isspace(c)) > - break; > - > - *p++ = c; > - } > - > - *p = 0; > - if (p == dst) > - return NULL; > - return p; > -} > > #define NEXT_LINE(loop_cond) do { \ > if (!fgets(line, sizeof(line), f)) { \ > @@ -593,505 +560,6 @@ static char* fget_next_word(char* dst, int max, FILE* f) > } \ > } while (loop_cond) > > -#define NEXT_LINE_OR_GOTO(loop_cond, label) do { \ > - if (!fgets(line, sizeof(line), f)) { \ > - av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \ > - ret = AVERROR_INVALIDDATA; \ > - goto label; \ > - } \ > -} while (loop_cond) > - > -static int allocate_3dlut(AVFilterContext *ctx, int lutsize, int prelut) > -{ > - LUT3DContext *lut3d = ctx->priv; > - int i; > - if (lutsize < 2 || lutsize > MAX_LEVEL) { > - av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n"); > - return AVERROR(EINVAL); > - } > - > - av_freep(&lut3d->lut); > - lut3d->lut = av_malloc_array(lutsize * lutsize * lutsize, sizeof(*lut3d- > >lut)); > - if (!lut3d->lut) > - return AVERROR(ENOMEM); > - > - if (prelut) { > - lut3d->prelut.size = PRELUT_SIZE; > - for (i = 0; i < 3; i++) { > - av_freep(&lut3d->prelut.lut[i]); > - lut3d->prelut.lut[i] = av_malloc_array(PRELUT_SIZE, > sizeof(*lut3d->prelut.lut[0])); > - if (!lut3d->prelut.lut[i]) > - return AVERROR(ENOMEM); > - } > - } else { > - lut3d->prelut.size = 0; > - for (i = 0; i < 3; i++) { > - av_freep(&lut3d->prelut.lut[i]); > - } > - } > - lut3d->lutsize = lutsize; > - lut3d->lutsize2 = lutsize * lutsize; > - return 0; > -} > - > -/* Basically r g and b float values on each line, with a facultative > 3DLUTSIZE > - * directive; seems to be generated by Davinci */ > -static int parse_dat(AVFilterContext *ctx, FILE *f) > -{ > - LUT3DContext *lut3d = ctx->priv; > - char line[MAX_LINE_SIZE]; > - int ret, i, j, k, size, size2; > - > - lut3d->lutsize = size = 33; > - size2 = size * size; > - > - NEXT_LINE(skip_line(line)); > - if (!strncmp(line, "3DLUTSIZE ", 10)) { > - size = strtol(line + 10, NULL, 0); > - > - NEXT_LINE(skip_line(line)); > - } > - > - ret = allocate_3dlut(ctx, size, 0); > - if (ret < 0) > - return ret; > - > - for (k = 0; k < size; k++) { > - for (j = 0; j < size; j++) { > - for (i = 0; i < size; i++) { > - struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > - if (k != 0 || j != 0 || i != 0) > - NEXT_LINE(skip_line(line)); > - if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != > 3) > - return AVERROR_INVALIDDATA; > - } > - } > - } > - return 0; > -} > - > -/* Iridas format */ > -static int parse_cube(AVFilterContext *ctx, FILE *f) > -{ > - LUT3DContext *lut3d = ctx->priv; > - char line[MAX_LINE_SIZE]; > - float min[3] = {0.0, 0.0, 0.0}; > - float max[3] = {1.0, 1.0, 1.0}; > - > - while (fgets(line, sizeof(line), f)) { > - if (!strncmp(line, "LUT_3D_SIZE", 11)) { > - int ret, i, j, k; > - const int size = strtol(line + 12, NULL, 0); > - const int size2 = size * size; > - > - ret = allocate_3dlut(ctx, size, 0); > - if (ret < 0) > - return ret; > - > - for (k = 0; k < size; k++) { > - for (j = 0; j < size; j++) { > - for (i = 0; i < size; i++) { > - struct rgbvec *vec = &lut3d->lut[i * size2 + j * size > + k]; > - > - do { > -try_again: > - NEXT_LINE(0); > - if (!strncmp(line, "DOMAIN_", 7)) { > - float *vals = NULL; > - if (!strncmp(line + 7, "MIN ", 4)) vals > = min; > - else if (!strncmp(line + 7, "MAX ", 4)) vals > = max; > - if (!vals) > - return AVERROR_INVALIDDATA; > - av_sscanf(line + 11, "%f %f %f", vals, vals + > 1, vals + 2); > - av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | > max: %f %f %f\n", > - min[0], min[1], min[2], max[0], > max[1], max[2]); > - goto try_again; > - } else if (!strncmp(line, "TITLE", 5)) { > - goto try_again; > - } > - } while (skip_line(line)); > - if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, > &vec->b) != 3) > - return AVERROR_INVALIDDATA; > - } > - } > - } > - break; > - } > - } > - > - lut3d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f); > - lut3d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f); > - lut3d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f); > - > - return 0; > -} > - > -/* Assume 17x17x17 LUT with a 16-bit depth > - * FIXME: it seems there are various 3dl formats */ > -static int parse_3dl(AVFilterContext *ctx, FILE *f) > -{ > - char line[MAX_LINE_SIZE]; > - LUT3DContext *lut3d = ctx->priv; > - int ret, i, j, k; > - const int size = 17; > - const int size2 = 17 * 17; > - const float scale = 16*16*16; > - > - lut3d->lutsize = size; > - > - ret = allocate_3dlut(ctx, size, 0); > - if (ret < 0) > - return ret; > - > - NEXT_LINE(skip_line(line)); > - for (k = 0; k < size; k++) { > - for (j = 0; j < size; j++) { > - for (i = 0; i < size; i++) { > - int r, g, b; > - struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > - > - NEXT_LINE(skip_line(line)); > - if (av_sscanf(line, "%d %d %d", &r, &g, &b) != 3) > - return AVERROR_INVALIDDATA; > - vec->r = r / scale; > - vec->g = g / scale; > - vec->b = b / scale; > - } > - } > - } > - return 0; > -} > - > -/* Pandora format */ > -static int parse_m3d(AVFilterContext *ctx, FILE *f) > -{ > - LUT3DContext *lut3d = ctx->priv; > - float scale; > - int ret, i, j, k, size, size2, in = -1, out = -1; > - char line[MAX_LINE_SIZE]; > - uint8_t rgb_map[3] = {0, 1, 2}; > - > - while (fgets(line, sizeof(line), f)) { > - if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0); > - else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0); > - else if (!strncmp(line, "values", 6)) { > - const char *p = line + 6; > -#define SET_COLOR(id) do { \ > - while (av_isspace(*p)) \ > - p++; \ > - switch (*p) { \ > - case 'r': rgb_map[id] = 0; break; \ > - case 'g': rgb_map[id] = 1; break; \ > - case 'b': rgb_map[id] = 2; break; \ > - } \ > - while (*p && !av_isspace(*p)) \ > - p++; \ > -} while (0) > - SET_COLOR(0); > - SET_COLOR(1); > - SET_COLOR(2); > - break; > - } > - } > - > - if (in == -1 || out == -1) { > - av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n"); > - return AVERROR_INVALIDDATA; > - } > - if (in < 2 || out < 2 || > - in > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL || > - out > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL) { > - av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out); > - return AVERROR_INVALIDDATA; > - } > - for (size = 1; size*size*size < in; size++); > - lut3d->lutsize = size; > - size2 = size * size; > - > - ret = allocate_3dlut(ctx, size, 0); > - if (ret < 0) > - return ret; > - > - scale = 1. / (out - 1); > - > - for (k = 0; k < size; k++) { > - for (j = 0; j < size; j++) { > - for (i = 0; i < size; i++) { > - struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > - float val[3]; > - > - NEXT_LINE(0); > - if (av_sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3) > - return AVERROR_INVALIDDATA; > - vec->r = val[rgb_map[0]] * scale; > - vec->g = val[rgb_map[1]] * scale; > - vec->b = val[rgb_map[2]] * scale; > - } > - } > - } > - return 0; > -} > - > -static int nearest_sample_index(float *data, float x, int low, int hi) > -{ > - int mid; > - if (x < data[low]) > - return low; > - > - if (x > data[hi]) > - return hi; > - > - for (;;) { > - av_assert0(x >= data[low]); > - av_assert0(x <= data[hi]); > - av_assert0((hi-low) > 0); > - > - if (hi - low == 1) > - return low; > - > - mid = (low + hi) / 2; > - > - if (x < data[mid]) > - hi = mid; > - else > - low = mid; > - } > - > - return 0; > -} > - > -#define NEXT_FLOAT_OR_GOTO(value, label) \ > - if (!fget_next_word(line, sizeof(line) ,f)) { \ > - ret = AVERROR_INVALIDDATA; \ > - goto label; \ > - } \ > - if (av_sscanf(line, "%f", &value) != 1) { \ > - ret = AVERROR_INVALIDDATA; \ > - goto label; \ > - } > - > -static int parse_cinespace(AVFilterContext *ctx, FILE *f) > -{ > - LUT3DContext *lut3d = ctx->priv; > - char line[MAX_LINE_SIZE]; > - float in_min[3] = {0.0, 0.0, 0.0}; > - float in_max[3] = {1.0, 1.0, 1.0}; > - float out_min[3] = {0.0, 0.0, 0.0}; > - float out_max[3] = {1.0, 1.0, 1.0}; > - int inside_metadata = 0, size, size2; > - int prelut = 0; > - int ret = 0; > - > - int prelut_sizes[3] = {0, 0, 0}; > - float *in_prelut[3] = {NULL, NULL, NULL}; > - float *out_prelut[3] = {NULL, NULL, NULL}; > - > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - if (strncmp(line, "CSPLUTV100", 10)) { > - av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n"); > - ret = AVERROR(EINVAL); > - goto end; > - } > - > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - if (strncmp(line, "3D", 2)) { > - av_log(ctx, AV_LOG_ERROR, "Not 3D LUT format\n"); > - ret = AVERROR(EINVAL); > - goto end; > - } > - > - while (1) { > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - > - if (!strncmp(line, "BEGIN METADATA", 14)) { > - inside_metadata = 1; > - continue; > - } > - if (!strncmp(line, "END METADATA", 12)) { > - inside_metadata = 0; > - continue; > - } > - if (inside_metadata == 0) { > - int size_r, size_g, size_b; > - > - for (int i = 0; i < 3; i++) { > - int npoints = strtol(line, NULL, 0); > - > - if (npoints > 2) { > - float v,last; > - > - if (npoints > PRELUT_SIZE) { > - av_log(ctx, AV_LOG_ERROR, "Prelut size too > large.\n"); > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - > - if (in_prelut[i] || out_prelut[i]) { > - av_log(ctx, AV_LOG_ERROR, "Invalid file has multiple > preluts.\n"); > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - > - in_prelut[i] = (float*)av_malloc(npoints * > sizeof(float)); > - out_prelut[i] = (float*)av_malloc(npoints * > sizeof(float)); > - if (!in_prelut[i] || !out_prelut[i]) { > - ret = AVERROR(ENOMEM); > - goto end; > - } > - > - prelut_sizes[i] = npoints; > - in_min[i] = FLT_MAX; > - in_max[i] = -FLT_MAX; > - out_min[i] = FLT_MAX; > - out_max[i] = -FLT_MAX; > - > - for (int j = 0; j < npoints; j++) { > - NEXT_FLOAT_OR_GOTO(v, end) > - in_min[i] = FFMIN(in_min[i], v); > - in_max[i] = FFMAX(in_max[i], v); > - in_prelut[i][j] = v; > - if (j > 0 && v < last) { > - av_log(ctx, AV_LOG_ERROR, "Invalid file, non > increasing prelut.\n"); > - ret = AVERROR(ENOMEM); > - goto end; > - } > - last = v; > - } > - > - for (int j = 0; j < npoints; j++) { > - NEXT_FLOAT_OR_GOTO(v, end) > - out_min[i] = FFMIN(out_min[i], v); > - out_max[i] = FFMAX(out_max[i], v); > - out_prelut[i][j] = v; > - } > - > - } else if (npoints == 2) { > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != > 2) { > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != > 2) { > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - > - } else { > - av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut > points.\n"); > - ret = AVERROR_PATCHWELCOME; > - goto end; > - } > - > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - } > - > - if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3) > { > - ret = AVERROR(EINVAL); > - goto end; > - } > - if (size_r != size_g || size_r != size_b) { > - av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: > %dx%dx%d.\n", size_r, size_g, size_b); > - ret = AVERROR_PATCHWELCOME; > - goto end; > - } > - > - size = size_r; > - size2 = size * size; > - > - if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2]) > - prelut = 1; > - > - ret = allocate_3dlut(ctx, size, prelut); > - if (ret < 0) > - return ret; > - > - for (int k = 0; k < size; k++) { > - for (int j = 0; j < size; j++) { > - for (int i = 0; i < size; i++) { > - struct rgbvec *vec = &lut3d->lut[i * size2 + j * size > + k]; > - > - NEXT_LINE_OR_GOTO(skip_line(line), end); > - if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, > &vec->b) != 3) { > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - > - vec->r *= out_max[0] - out_min[0]; > - vec->g *= out_max[1] - out_min[1]; > - vec->b *= out_max[2] - out_min[2]; > - } > - } > - } > - > - break; > - } > - } > - > - if (prelut) { > - for (int c = 0; c < 3; c++) { > - > - lut3d->prelut.min[c] = in_min[c]; > - lut3d->prelut.max[c] = in_max[c]; > - lut3d->prelut.scale[c] = (1.0f / (float)(in_max[c] - in_min[c])) > * (lut3d->prelut.size - 1); > - > - for (int i = 0; i < lut3d->prelut.size; ++i) { > - float mix = (float) i / (float)(lut3d->prelut.size - 1); > - float x = lerpf(in_min[c], in_max[c], mix), a, b; > - > - int idx = nearest_sample_index(in_prelut[c], x, 0, > prelut_sizes[c]-1); > - av_assert0(idx + 1 < prelut_sizes[c]); > - > - a = out_prelut[c][idx + 0]; > - b = out_prelut[c][idx + 1]; > - mix = x - in_prelut[c][idx]; > - > - lut3d->prelut.lut[c][i] = sanitizef(lerpf(a, b, mix)); > - } > - } > - lut3d->scale.r = 1.00f; > - lut3d->scale.g = 1.00f; > - lut3d->scale.b = 1.00f; > - > - } else { > - lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f); > - lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f); > - lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f); > - } > - > -end: > - for (int c = 0; c < 3; c++) { > - av_freep(&in_prelut[c]); > - av_freep(&out_prelut[c]); > - } > - return ret; > -} > - > -static int set_identity_matrix(AVFilterContext *ctx, int size) > -{ > - LUT3DContext *lut3d = ctx->priv; > - int ret, i, j, k; > - const int size2 = size * size; > - const float c = 1. / (size - 1); > - > - ret = allocate_3dlut(ctx, size, 0); > - if (ret < 0) > - return ret; > - > - for (k = 0; k < size; k++) { > - for (j = 0; j < size; j++) { > - for (i = 0; i < size; i++) { > - struct rgbvec *vec = &lut3d->lut[k * size2 + j * size + i]; > - vec->r = k * c; > - vec->g = j * c; > - vec->b = i * c; > - } > - } > - } > - > - return 0; > -} > - > static const enum AVPixelFormat pix_fmts[] = { > AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, > AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, > @@ -1230,66 +698,14 @@ AVFILTER_DEFINE_CLASS_EXT(lut3d, "lut3d", > lut3d_haldclut_options); > > static av_cold int lut3d_init(AVFilterContext *ctx) > { > - int ret; > - FILE *f; > - const char *ext; > LUT3DContext *lut3d = ctx->priv; > - > - lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f; > - > - if (!lut3d->file) { > - return set_identity_matrix(ctx, 32); > - } > - > - f = avpriv_fopen_utf8(lut3d->file, "r"); > - if (!f) { > - ret = AVERROR(errno); > - av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret)); > - return ret; > - } > - > - ext = strrchr(lut3d->file, '.'); > - if (!ext) { > - av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the > extension\n"); > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - ext++; > - > - if (!av_strcasecmp(ext, "dat")) { > - ret = parse_dat(ctx, f); > - } else if (!av_strcasecmp(ext, "3dl")) { > - ret = parse_3dl(ctx, f); > - } else if (!av_strcasecmp(ext, "cube")) { > - ret = parse_cube(ctx, f); > - } else if (!av_strcasecmp(ext, "m3d")) { > - ret = parse_m3d(ctx, f); > - } else if (!av_strcasecmp(ext, "csp")) { > - ret = parse_cinespace(ctx, f); > - } else { > - av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext); > - ret = AVERROR(EINVAL); > - } > - > - if (!ret && !lut3d->lutsize) { > - av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n"); > - ret = AVERROR_INVALIDDATA; > - } > - > -end: > - fclose(f); > - return ret; > + return ff_lut3d_init(ctx, lut3d); > } > > static av_cold void lut3d_uninit(AVFilterContext *ctx) > { > LUT3DContext *lut3d = ctx->priv; > - int i; > - av_freep(&lut3d->lut); > - > - for (i = 0; i < 3; i++) { > - av_freep(&lut3d->prelut.lut[i]); > - } > + ff_lut3d_uninit(lut3d); > } > > static const AVFilterPad lut3d_inputs[] = { > @@ -1499,7 +915,7 @@ static int config_clut(AVFilterLink *inlink) > return AVERROR(EINVAL); > } > > - return allocate_3dlut(ctx, level, 0); > + return ff_allocate_3dlut(ctx, lut3d, level, 0); > } > > static int update_apply_clut(FFFrameSync *fs) _______________________________________________ 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".
next prev parent reply other threads:[~2023-10-16 7:52 UTC|newest] Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top 2023-09-23 15:36 [FFmpeg-devel] [PATCH 0/2] avfilter/vf_vpp_qsv: apply 3D LUT from file Chen Yufei 2023-09-23 15:36 ` [FFmpeg-devel] [PATCH 1/2] avfilter/vf_lut3d: expose 3D LUT file parse function Chen Yufei 2023-10-16 7:51 ` Xiang, Haihao [this message] 2023-10-23 1:16 ` Chen Yufei 2023-09-23 15:36 ` [FFmpeg-devel] [PATCH 2/2] avfilter/vf_vpp_qsv: apply 3D LUT from file Chen Yufei 2023-10-16 8:05 ` Xiang, Haihao 2023-10-23 1:27 ` Chen Yufei
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=d3bfd7be73b3ee405c00ab3084ac55a63e8a48c9.camel@intel.com \ --to=haihao.xiang-at-intel.com@ffmpeg.org \ --cc=cyfdecyf@gmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git