Go to the documentation of this file.
46 #define OFFSET(x) offsetof(LUT3DContext, x)
47 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
48 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
49 #define COMMON_OPTIONS \
50 { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, TFLAGS, "interp_mode" }, \
51 { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, 0, 0, TFLAGS, "interp_mode" }, \
52 { "trilinear", "interpolate values using the 8 points defining a cube", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TRILINEAR}, 0, 0, TFLAGS, "interp_mode" }, \
53 { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, 0, TFLAGS, "interp_mode" }, \
54 { "pyramid", "interpolate values using a pyramid", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_PYRAMID}, 0, 0, TFLAGS, "interp_mode" }, \
55 { "prism", "interpolate values using a prism", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_PRISM}, 0, 0, TFLAGS, "interp_mode" }, \
58 #define EXPONENT_MASK 0x7F800000
59 #define MANTISSA_MASK 0x007FFFFF
60 #define SIGN_MASK 0x80000000
82 static inline float lerpf(
float v0,
float v1,
float f)
84 return v0 + (v1 -
v0) *
f;
95 #define NEAR(x) ((int)((x) + .5))
96 #define PREV(x) ((int)(x))
97 #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
105 return lut3d->lut[
NEAR(
s->r) * lut3d->lutsize2 +
NEAR(
s->g) * lut3d->lutsize +
NEAR(
s->b)];
115 const int lutsize2 = lut3d->lutsize2;
116 const int lutsize = lut3d->lutsize;
119 const struct rgbvec d = {
s->r - prev[0],
s->g - prev[1],
s->b - prev[2]};
120 const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
121 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
122 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
123 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
124 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
125 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
126 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
127 const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
141 const int lutsize2 = lut3d->lutsize2;
142 const int lutsize = lut3d->lutsize;
145 const struct rgbvec d = {
s->r - prev[0],
s->g - prev[1],
s->b - prev[2]};
146 const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
147 const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
150 if (
d.g >
d.r &&
d.b >
d.r) {
151 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
152 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
153 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
155 c.r = c000.
r + (c111.
r - c011.
r) *
d.r + (c010.
r - c000.
r) *
d.g + (c001.
r - c000.
r) *
d.b +
156 (c011.
r - c001.
r - c010.
r + c000.
r) *
d.g *
d.b;
157 c.g = c000.
g + (c111.
g - c011.
g) *
d.r + (c010.
g - c000.
g) *
d.g + (c001.
g - c000.
g) *
d.b +
158 (c011.
g - c001.
g - c010.
g + c000.
g) *
d.g *
d.b;
159 c.b = c000.
b + (c111.
b - c011.
b) *
d.r + (c010.
b - c000.
b) *
d.g + (c001.
b - c000.
b) *
d.b +
160 (c011.
b - c001.
b - c010.
b + c000.
b) *
d.g *
d.b;
161 }
else if (
d.r >
d.g &&
d.b >
d.g) {
162 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
163 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
164 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
166 c.r = c000.
r + (c100.
r - c000.
r) *
d.r + (c111.
r - c101.
r) *
d.g + (c001.
r - c000.
r) *
d.b +
167 (c101.
r - c001.
r - c100.
r + c000.
r) *
d.r *
d.b;
168 c.g = c000.
g + (c100.
g - c000.
g) *
d.r + (c111.
g - c101.
g) *
d.g + (c001.
g - c000.
g) *
d.b +
169 (c101.
g - c001.
g - c100.
g + c000.
g) *
d.r *
d.b;
170 c.b = c000.
b + (c100.
b - c000.
b) *
d.r + (c111.
b - c101.
b) *
d.g + (c001.
b - c000.
b) *
d.b +
171 (c101.
b - c001.
b - c100.
b + c000.
b) *
d.r *
d.b;
173 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
174 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
175 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
177 c.r = c000.
r + (c100.
r - c000.
r) *
d.r + (c010.
r - c000.
r) *
d.g + (c111.
r - c110.
r) *
d.b +
178 (c110.
r - c100.
r - c010.
r + c000.
r) *
d.r *
d.g;
179 c.g = c000.
g + (c100.
g - c000.
g) *
d.r + (c010.
g - c000.
g) *
d.g + (c111.
g - c110.
g) *
d.b +
180 (c110.
g - c100.
g - c010.
g + c000.
g) *
d.r *
d.g;
181 c.b = c000.
b + (c100.
b - c000.
b) *
d.r + (c010.
b - c000.
b) *
d.g + (c111.
b - c110.
b) *
d.b +
182 (c110.
b - c100.
b - c010.
b + c000.
b) *
d.r *
d.g;
191 const int lutsize2 = lut3d->lutsize2;
192 const int lutsize = lut3d->lutsize;
195 const struct rgbvec d = {
s->r - prev[0],
s->g - prev[1],
s->b - prev[2]};
196 const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
197 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
198 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
199 const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
203 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
204 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
206 c.r = c000.
r + (c001.
r - c000.
r) *
d.b + (c101.
r - c001.
r) *
d.r + (c010.
r - c000.
r) *
d.g +
207 (c000.
r - c010.
r - c001.
r + c011.
r) *
d.b *
d.g +
208 (c001.
r - c011.
r - c101.
r + c111.
r) *
d.r *
d.g;
209 c.g = c000.
g + (c001.
g - c000.
g) *
d.b + (c101.
g - c001.
g) *
d.r + (c010.
g - c000.
g) *
d.g +
210 (c000.
g - c010.
g - c001.
g + c011.
g) *
d.b *
d.g +
211 (c001.
g - c011.
g - c101.
g + c111.
g) *
d.r *
d.g;
212 c.b = c000.
b + (c001.
b - c000.
b) *
d.b + (c101.
b - c001.
b) *
d.r + (c010.
b - c000.
b) *
d.g +
213 (c000.
b - c010.
b - c001.
b + c011.
b) *
d.b *
d.g +
214 (c001.
b - c011.
b - c101.
b + c111.
b) *
d.r *
d.g;
216 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
217 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
219 c.r = c000.
r + (c101.
r - c100.
r) *
d.b + (c100.
r - c000.
r) *
d.r + (c010.
r - c000.
r) *
d.g +
220 (c100.
r - c110.
r - c101.
r + c111.
r) *
d.b *
d.g +
221 (c000.
r - c010.
r - c100.
r + c110.
r) *
d.r *
d.g;
222 c.g = c000.
g + (c101.
g - c100.
g) *
d.b + (c100.
g - c000.
g) *
d.r + (c010.
g - c000.
g) *
d.g +
223 (c100.
g - c110.
g - c101.
g + c111.
g) *
d.b *
d.g +
224 (c000.
g - c010.
g - c100.
g + c110.
g) *
d.r *
d.g;
225 c.b = c000.
b + (c101.
b - c100.
b) *
d.b + (c100.
b - c000.
b) *
d.r + (c010.
b - c000.
b) *
d.g +
226 (c100.
b - c110.
b - c101.
b + c111.
b) *
d.b *
d.g +
227 (c000.
b - c010.
b - c100.
b + c110.
b) *
d.r *
d.g;
240 const int lutsize2 = lut3d->lutsize2;
241 const int lutsize = lut3d->lutsize;
244 const struct rgbvec d = {
s->r - prev[0],
s->g - prev[1],
s->b - prev[2]};
245 const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
246 const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
250 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
251 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
252 c.r = (1-
d.r) * c000.
r + (
d.r-
d.g) * c100.
r + (
d.g-
d.b) * c110.
r + (
d.b) * c111.
r;
253 c.g = (1-
d.r) * c000.
g + (
d.r-
d.g) * c100.
g + (
d.g-
d.b) * c110.
g + (
d.b) * c111.
g;
254 c.b = (1-
d.r) * c000.
b + (
d.r-
d.g) * c100.
b + (
d.g-
d.b) * c110.
b + (
d.b) * c111.
b;
255 }
else if (
d.r >
d.b) {
256 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
257 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
258 c.r = (1-
d.r) * c000.
r + (
d.r-
d.b) * c100.
r + (
d.b-
d.g) * c101.
r + (
d.g) * c111.
r;
259 c.g = (1-
d.r) * c000.
g + (
d.r-
d.b) * c100.
g + (
d.b-
d.g) * c101.
g + (
d.g) * c111.
g;
260 c.b = (1-
d.r) * c000.
b + (
d.r-
d.b) * c100.
b + (
d.b-
d.g) * c101.
b + (
d.g) * c111.
b;
262 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
263 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
264 c.r = (1-
d.b) * c000.
r + (
d.b-
d.r) * c001.
r + (
d.r-
d.g) * c101.
r + (
d.g) * c111.
r;
265 c.g = (1-
d.b) * c000.
g + (
d.b-
d.r) * c001.
g + (
d.r-
d.g) * c101.
g + (
d.g) * c111.
g;
266 c.b = (1-
d.b) * c000.
b + (
d.b-
d.r) * c001.
b + (
d.r-
d.g) * c101.
b + (
d.g) * c111.
b;
270 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
271 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
272 c.r = (1-
d.b) * c000.
r + (
d.b-
d.g) * c001.
r + (
d.g-
d.r) * c011.
r + (
d.r) * c111.
r;
273 c.g = (1-
d.b) * c000.
g + (
d.b-
d.g) * c001.
g + (
d.g-
d.r) * c011.
g + (
d.r) * c111.
g;
274 c.b = (1-
d.b) * c000.
b + (
d.b-
d.g) * c001.
b + (
d.g-
d.r) * c011.
b + (
d.r) * c111.
b;
275 }
else if (
d.b >
d.r) {
276 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
277 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
278 c.r = (1-
d.g) * c000.
r + (
d.g-
d.b) * c010.
r + (
d.b-
d.r) * c011.
r + (
d.r) * c111.
r;
279 c.g = (1-
d.g) * c000.
g + (
d.g-
d.b) * c010.
g + (
d.b-
d.r) * c011.
g + (
d.r) * c111.
g;
280 c.b = (1-
d.g) * c000.
b + (
d.g-
d.b) * c010.
b + (
d.b-
d.r) * c011.
b + (
d.r) * c111.
b;
282 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
283 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
284 c.r = (1-
d.g) * c000.
r + (
d.g-
d.r) * c010.
r + (
d.r-
d.b) * c110.
r + (
d.b) * c111.
r;
285 c.g = (1-
d.g) * c000.
g + (
d.g-
d.r) * c010.
g + (
d.r-
d.b) * c110.
g + (
d.b) * c111.
g;
286 c.b = (1-
d.g) * c000.
b + (
d.g-
d.r) * c010.
b + (
d.r-
d.b) * c110.
b + (
d.b) * c111.
b;
293 int idx,
const float s)
295 const int lut_max = prelut->
size - 1;
296 const float scaled = (
s - prelut->
min[idx]) * prelut->
scale[idx];
297 const float x =
av_clipf(scaled, 0.0
f, lut_max);
298 const int prev =
PREV(x);
299 const int next =
FFMIN((
int)(x) + 1, lut_max);
300 const float p = prelut->
lut[idx][prev];
301 const float n = prelut->
lut[idx][next];
302 const float d = x - (float)prev;
311 if (prelut->size <= 0)
320 #define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \
321 static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
324 const LUT3DContext *lut3d = ctx->priv; \
325 const Lut3DPreLut *prelut = &lut3d->prelut; \
326 const ThreadData *td = arg; \
327 const AVFrame *in = td->in; \
328 const AVFrame *out = td->out; \
329 const int direct = out == in; \
330 const int slice_start = (in->height * jobnr ) / nb_jobs; \
331 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
332 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
333 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
334 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
335 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
336 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
337 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
338 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
339 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
340 const float lut_max = lut3d->lutsize - 1; \
341 const float scale_f = 1.0f / ((1<<depth) - 1); \
342 const float scale_r = lut3d->scale.r * lut_max; \
343 const float scale_g = lut3d->scale.g * lut_max; \
344 const float scale_b = lut3d->scale.b * lut_max; \
346 for (y = slice_start; y < slice_end; y++) { \
347 uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
348 uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
349 uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
350 uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
351 const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
352 const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
353 const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
354 const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
355 for (x = 0; x < in->width; x++) { \
356 const struct rgbvec rgb = {srcr[x] * scale_f, \
358 srcb[x] * scale_f}; \
359 const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
360 const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
361 av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
362 av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
363 struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
364 dstr[x] = av_clip_uintp2(vec.r * (float)((1<<depth) - 1), depth); \
365 dstg[x] = av_clip_uintp2(vec.g * (float)((1<<depth) - 1), depth); \
366 dstb[x] = av_clip_uintp2(vec.b * (float)((1<<depth) - 1), depth); \
367 if (!direct && in->linesize[3]) \
370 grow += out->linesize[0]; \
371 brow += out->linesize[1]; \
372 rrow += out->linesize[2]; \
373 arow += out->linesize[3]; \
374 srcgrow += in->linesize[0]; \
375 srcbrow += in->linesize[1]; \
376 srcrrow += in->linesize[2]; \
377 srcarow += in->linesize[3]; \
418 #define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth) \
419 static int interp_##name##_pf##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
422 const LUT3DContext *lut3d = ctx->priv; \
423 const Lut3DPreLut *prelut = &lut3d->prelut; \
424 const ThreadData *td = arg; \
425 const AVFrame *in = td->in; \
426 const AVFrame *out = td->out; \
427 const int direct = out == in; \
428 const int slice_start = (in->height * jobnr ) / nb_jobs; \
429 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
430 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
431 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
432 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
433 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
434 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
435 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
436 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
437 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
438 const float lut_max = lut3d->lutsize - 1; \
439 const float scale_r = lut3d->scale.r * lut_max; \
440 const float scale_g = lut3d->scale.g * lut_max; \
441 const float scale_b = lut3d->scale.b * lut_max; \
443 for (y = slice_start; y < slice_end; y++) { \
444 float *dstg = (float *)grow; \
445 float *dstb = (float *)brow; \
446 float *dstr = (float *)rrow; \
447 float *dsta = (float *)arow; \
448 const float *srcg = (const float *)srcgrow; \
449 const float *srcb = (const float *)srcbrow; \
450 const float *srcr = (const float *)srcrrow; \
451 const float *srca = (const float *)srcarow; \
452 for (x = 0; x < in->width; x++) { \
453 const struct rgbvec rgb = {sanitizef(srcr[x]), \
454 sanitizef(srcg[x]), \
455 sanitizef(srcb[x])}; \
456 const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
457 const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
458 av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
459 av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
460 struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
464 if (!direct && in->linesize[3]) \
467 grow += out->linesize[0]; \
468 brow += out->linesize[1]; \
469 rrow += out->linesize[2]; \
470 arow += out->linesize[3]; \
471 srcgrow += in->linesize[0]; \
472 srcbrow += in->linesize[1]; \
473 srcrrow += in->linesize[2]; \
474 srcarow += in->linesize[3]; \
485 #define DEFINE_INTERP_FUNC(name, nbits) \
486 static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
489 const LUT3DContext *lut3d = ctx->priv; \
490 const Lut3DPreLut *prelut = &lut3d->prelut; \
491 const ThreadData *td = arg; \
492 const AVFrame *in = td->in; \
493 const AVFrame *out = td->out; \
494 const int direct = out == in; \
495 const int step = lut3d->step; \
496 const uint8_t r = lut3d->rgba_map[R]; \
497 const uint8_t g = lut3d->rgba_map[G]; \
498 const uint8_t b = lut3d->rgba_map[B]; \
499 const uint8_t a = lut3d->rgba_map[A]; \
500 const int slice_start = (in->height * jobnr ) / nb_jobs; \
501 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
502 uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
503 const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
504 const float lut_max = lut3d->lutsize - 1; \
505 const float scale_f = 1.0f / ((1<<nbits) - 1); \
506 const float scale_r = lut3d->scale.r * lut_max; \
507 const float scale_g = lut3d->scale.g * lut_max; \
508 const float scale_b = lut3d->scale.b * lut_max; \
510 for (y = slice_start; y < slice_end; y++) { \
511 uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
512 const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
513 for (x = 0; x < in->width * step; x += step) { \
514 const struct rgbvec rgb = {src[x + r] * scale_f, \
515 src[x + g] * scale_f, \
516 src[x + b] * scale_f}; \
517 const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
518 const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
519 av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
520 av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
521 struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
522 dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
523 dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
524 dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
525 if (!direct && step == 4) \
526 dst[x + a] = src[x + a]; \
528 dstrow += out->linesize[0]; \
529 srcrow += in ->linesize[0]; \
546 #define MAX_LINE_SIZE 512
552 return !*p || *p ==
'#';
563 while ((
c = fgetc(
f)) != EOF) {
574 if ((
c = fgetc(
f)) == EOF)
589 #define NEXT_LINE(loop_cond) do { \
590 if (!fgets(line, sizeof(line), f)) { \
591 av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
592 return AVERROR_INVALIDDATA; \
596 #define NEXT_LINE_OR_GOTO(loop_cond, label) do { \
597 if (!fgets(line, sizeof(line), f)) { \
598 av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
599 ret = AVERROR_INVALIDDATA; \
608 if (lutsize < 2 || lutsize >
MAX_LEVEL) {
620 for (
i = 0;
i < 3;
i++) {
628 for (
i = 0;
i < 3;
i++) {
633 lut3d->
lutsize2 = lutsize * lutsize;
649 if (!strncmp(
line,
"3DLUTSIZE ", 10)) {
659 for (k = 0; k <
size; k++) {
660 for (j = 0; j <
size; j++) {
663 if (k != 0 || j != 0 ||
i != 0)
678 float min[3] = {0.0, 0.0, 0.0};
679 float max[3] = {1.0, 1.0, 1.0};
682 if (!strncmp(
line,
"LUT_3D_SIZE", 11)) {
691 for (k = 0; k <
size; k++) {
692 for (j = 0; j <
size; j++) {
699 if (!strncmp(
line,
"DOMAIN_", 7)) {
701 if (!strncmp(
line + 7,
"MIN ", 4)) vals =
min;
702 else if (!strncmp(
line + 7,
"MAX ", 4)) vals =
max;
709 }
else if (!strncmp(
line,
"TITLE", 5)) {
737 const int size2 = 17 * 17;
738 const float scale = 16*16*16;
747 for (k = 0; k <
size; k++) {
748 for (j = 0; j <
size; j++) {
772 uint8_t rgb_map[3] = {0, 1, 2};
775 if (!strncmp(
line,
"in", 2)) in = strtol(
line + 2,
NULL, 0);
777 else if (!strncmp(
line,
"values", 6)) {
778 const char *p =
line + 6;
779 #define SET_COLOR(id) do { \
780 while (av_isspace(*p)) \
783 case 'r': rgb_map[id] = 0; break; \
784 case 'g': rgb_map[id] = 1; break; \
785 case 'b': rgb_map[id] = 2; break; \
787 while (*p && !av_isspace(*p)) \
797 if (in == -1 ||
out == -1) {
801 if (in < 2 ||
out < 2 ||
817 for (k = 0; k <
size; k++) {
818 for (j = 0; j <
size; j++) {
852 mid = (low + hi) / 2;
863 #define NEXT_FLOAT_OR_GOTO(value, label) \
864 if (!fget_next_word(line, sizeof(line) ,f)) { \
865 ret = AVERROR_INVALIDDATA; \
868 if (av_sscanf(line, "%f", &value) != 1) { \
869 ret = AVERROR_INVALIDDATA; \
877 float in_min[3] = {0.0, 0.0, 0.0};
878 float in_max[3] = {1.0, 1.0, 1.0};
879 float out_min[3] = {0.0, 0.0, 0.0};
880 float out_max[3] = {1.0, 1.0, 1.0};
881 int inside_metadata = 0,
size, size2;
885 int prelut_sizes[3] = {0, 0, 0};
890 if (strncmp(
line,
"CSPLUTV100", 10)) {
897 if (strncmp(
line,
"3D", 2)) {
906 if (!strncmp(
line,
"BEGIN METADATA", 14)) {
910 if (!strncmp(
line,
"END METADATA", 12)) {
914 if (inside_metadata == 0) {
915 int size_r, size_g, size_b;
917 for (
int i = 0;
i < 3;
i++) {
918 int npoints = strtol(
line,
NULL, 0);
929 if (in_prelut[
i] || out_prelut[
i]) {
935 in_prelut[
i] = (
float*)
av_malloc(npoints *
sizeof(
float));
936 out_prelut[
i] = (
float*)
av_malloc(npoints *
sizeof(
float));
937 if (!in_prelut[
i] || !out_prelut[
i]) {
942 prelut_sizes[
i] = npoints;
944 in_max[
i] = -FLT_MAX;
945 out_min[
i] = FLT_MAX;
946 out_max[
i] = -FLT_MAX;
948 for (
int j = 0; j < npoints; j++) {
950 in_min[
i] =
FFMIN(in_min[
i], v);
951 in_max[
i] =
FFMAX(in_max[
i], v);
953 if (j > 0 && v < last) {
961 for (
int j = 0; j < npoints; j++) {
963 out_min[
i] =
FFMIN(out_min[
i], v);
964 out_max[
i] =
FFMAX(out_max[
i], v);
965 out_prelut[
i][j] = v;
968 }
else if (npoints == 2) {
989 if (
av_sscanf(
line,
"%d %d %d", &size_r, &size_g, &size_b) != 3) {
993 if (size_r != size_g || size_r != size_b) {
1002 if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2])
1009 for (
int k = 0; k <
size; k++) {
1010 for (
int j = 0; j <
size; j++) {
1011 for (
int i = 0;
i <
size;
i++) {
1020 vec->
r *= out_max[0] - out_min[0];
1021 vec->
g *= out_max[1] - out_min[1];
1022 vec->
b *= out_max[2] - out_min[2];
1032 for (
int c = 0;
c < 3;
c++) {
1045 a = out_prelut[
c][idx + 0];
1046 b = out_prelut[
c][idx + 1];
1047 mix = x - in_prelut[
c][idx];
1063 for (
int c = 0;
c < 3;
c++) {
1075 const float c = 1. / (
size - 1);
1081 for (k = 0; k <
size; k++) {
1082 for (j = 0; j <
size; j++) {
1115 int depth, is16bit, isfloat,
planar;
1119 depth =
desc->comp[0].depth;
1120 is16bit =
desc->comp[0].depth > 8;
1126 #define SET_FUNC(name) do { \
1127 if (planar && !isfloat) { \
1129 case 8: lut3d->interp = interp_8_##name##_p8; break; \
1130 case 9: lut3d->interp = interp_16_##name##_p9; break; \
1131 case 10: lut3d->interp = interp_16_##name##_p10; break; \
1132 case 12: lut3d->interp = interp_16_##name##_p12; break; \
1133 case 14: lut3d->interp = interp_16_##name##_p14; break; \
1134 case 16: lut3d->interp = interp_16_##name##_p16; break; \
1136 } else if (isfloat) { lut3d->interp = interp_##name##_pf32; \
1137 } else if (is16bit) { lut3d->interp = interp_16_##name; \
1138 } else { lut3d->interp = interp_8_##name; } \
1198 char *res,
int res_len,
int flags)
1209 #if CONFIG_LUT3D_FILTER || CONFIG_HALDCLUT_FILTER
1214 #define COMMON_OPTIONS_OFFSET CONFIG_LUT3D_FILTER
1215 static const AVOption lut3d_haldclut_options[] = {
1216 #if CONFIG_LUT3D_FILTER
1222 #if CONFIG_LUT3D_FILTER
1246 ext = strrchr(lut3d->
file,
'.');
1285 for (
i = 0;
i < 3;
i++) {
1315 .priv_class = &lut3d_class,
1321 #if CONFIG_HALDCLUT_FILTER
1326 const int linesize =
frame->linesize[0];
1327 const int w = lut3d->clut_width;
1328 const int step = lut3d->clut_step;
1329 const uint8_t *rgba_map = lut3d->clut_rgba_map;
1331 const int level2 = lut3d->
lutsize2;
1333 #define LOAD_CLUT(nbits) do { \
1334 int i, j, k, x = 0, y = 0; \
1336 for (k = 0; k < level; k++) { \
1337 for (j = 0; j < level; j++) { \
1338 for (i = 0; i < level; i++) { \
1339 const uint##nbits##_t *src = (const uint##nbits##_t *) \
1340 (data + y*linesize + x*step); \
1341 struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1342 vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
1343 vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
1344 vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
1354 switch (lut3d->clut_bits) {
1355 case 8: LOAD_CLUT(8);
break;
1356 case 16: LOAD_CLUT(16);
break;
1362 const uint8_t *datag =
frame->data[0];
1363 const uint8_t *datab =
frame->data[1];
1364 const uint8_t *datar =
frame->data[2];
1365 const int glinesize =
frame->linesize[0];
1366 const int blinesize =
frame->linesize[1];
1367 const int rlinesize =
frame->linesize[2];
1368 const int w = lut3d->clut_width;
1370 const int level2 = lut3d->
lutsize2;
1372 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
1373 int i, j, k, x = 0, y = 0; \
1375 for (k = 0; k < level; k++) { \
1376 for (j = 0; j < level; j++) { \
1377 for (i = 0; i < level; i++) { \
1378 const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
1379 (datag + y*glinesize); \
1380 const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
1381 (datab + y*blinesize); \
1382 const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
1383 (datar + y*rlinesize); \
1384 struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1385 vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
1386 vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
1387 vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
1397 switch (lut3d->clut_bits) {
1398 case 8: LOAD_CLUT_PLANAR(8, 8);
break;
1399 case 9: LOAD_CLUT_PLANAR(16, 9);
break;
1400 case 10: LOAD_CLUT_PLANAR(16, 10);
break;
1401 case 12: LOAD_CLUT_PLANAR(16, 12);
break;
1402 case 14: LOAD_CLUT_PLANAR(16, 14);
break;
1403 case 16: LOAD_CLUT_PLANAR(16, 16);
break;
1409 const uint8_t *datag =
frame->data[0];
1410 const uint8_t *datab =
frame->data[1];
1411 const uint8_t *datar =
frame->data[2];
1412 const int glinesize =
frame->linesize[0];
1413 const int blinesize =
frame->linesize[1];
1414 const int rlinesize =
frame->linesize[2];
1415 const int w = lut3d->clut_width;
1417 const int level2 = lut3d->
lutsize2;
1419 int i, j, k, x = 0, y = 0;
1421 for (k = 0; k <
level; k++) {
1422 for (j = 0; j <
level; j++) {
1424 const float *gsrc = (
const float *)(datag + y*glinesize);
1425 const float *bsrc = (
const float *)(datab + y*blinesize);
1426 const float *rsrc = (
const float *)(datar + y*rlinesize);
1449 outlink->
w =
ctx->inputs[0]->w;
1450 outlink->
h =
ctx->inputs[0]->h;
1472 lut3d->clut_bits =
desc->comp[0].depth;
1496 const int max_clut_level = sqrt(
MAX_LEVEL);
1497 const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1499 "(maximum level is %d, or %dx%d CLUT)\n",
1500 max_clut_level, max_clut_size, max_clut_size);
1520 if (lut3d->clut_float)
1521 update_clut_float(
ctx->priv, second);
1522 else if (lut3d->clut_planar)
1523 update_clut_planar(
ctx->priv, second);
1525 update_clut_packed(
ctx->priv, second);
1534 lut3d->fs.on_event = update_apply_clut;
1546 &lut3d_haldclut_options[COMMON_OPTIONS_OFFSET]);
1556 .config_props = config_clut,
1572 .
preinit = haldclut_framesync_preinit,
1573 .
init = haldclut_init,
1574 .
uninit = haldclut_uninit,
1579 .priv_class = &haldclut_class,
1587 #if CONFIG_LUT1D_FILTER
1589 enum interp_1d_mode {
1590 INTERPOLATE_1D_NEAREST,
1591 INTERPOLATE_1D_LINEAR,
1592 INTERPOLATE_1D_CUBIC,
1593 INTERPOLATE_1D_COSINE,
1594 INTERPOLATE_1D_SPLINE,
1598 #define MAX_1D_LEVEL 65536
1600 typedef struct LUT1DContext {
1605 uint8_t rgba_map[4];
1607 float lut[3][MAX_1D_LEVEL];
1613 #define OFFSET(x) offsetof(LUT1DContext, x)
1615 static void set_identity_matrix_1d(LUT1DContext *lut1d,
int size)
1617 const float c = 1. / (
size - 1);
1620 lut1d->lutsize =
size;
1622 lut1d->lut[0][
i] =
i *
c;
1623 lut1d->lut[1][
i] =
i *
c;
1624 lut1d->lut[2][
i] =
i *
c;
1630 LUT1DContext *lut1d =
ctx->priv;
1632 float in_min[3] = {0.0, 0.0, 0.0};
1633 float in_max[3] = {1.0, 1.0, 1.0};
1634 float out_min[3] = {0.0, 0.0, 0.0};
1635 float out_max[3] = {1.0, 1.0, 1.0};
1636 int inside_metadata = 0,
size;
1639 if (strncmp(
line,
"CSPLUTV100", 10)) {
1645 if (strncmp(
line,
"1D", 2)) {
1653 if (!strncmp(
line,
"BEGIN METADATA", 14)) {
1654 inside_metadata = 1;
1657 if (!strncmp(
line,
"END METADATA", 12)) {
1658 inside_metadata = 0;
1661 if (inside_metadata == 0) {
1662 for (
int i = 0;
i < 3;
i++) {
1663 int npoints = strtol(
line,
NULL, 0);
1681 if (size < 2 || size > MAX_1D_LEVEL) {
1686 lut1d->lutsize =
size;
1688 for (
int i = 0;
i <
size;
i++) {
1690 if (
av_sscanf(
line,
"%f %f %f", &lut1d->lut[0][
i], &lut1d->lut[1][
i], &lut1d->lut[2][
i]) != 3)
1692 lut1d->lut[0][
i] *= out_max[0] - out_min[0];
1693 lut1d->lut[1][
i] *= out_max[1] - out_min[1];
1694 lut1d->lut[2][
i] *= out_max[2] - out_min[2];
1701 lut1d->scale.r =
av_clipf(1. / (in_max[0] - in_min[0]), 0.
f, 1.
f);
1702 lut1d->scale.g =
av_clipf(1. / (in_max[1] - in_min[1]), 0.
f, 1.
f);
1703 lut1d->scale.b =
av_clipf(1. / (in_max[2] - in_min[2]), 0.
f, 1.
f);
1710 LUT1DContext *lut1d =
ctx->priv;
1712 float min[3] = {0.0, 0.0, 0.0};
1713 float max[3] = {1.0, 1.0, 1.0};
1716 if (!strncmp(
line,
"LUT_1D_SIZE", 11)) {
1720 if (size < 2 || size > MAX_1D_LEVEL) {
1724 lut1d->lutsize =
size;
1729 if (!strncmp(
line,
"DOMAIN_", 7)) {
1731 if (!strncmp(
line + 7,
"MIN ", 4)) vals =
min;
1732 else if (!strncmp(
line + 7,
"MAX ", 4)) vals =
max;
1739 }
else if (!strncmp(
line,
"LUT_1D_INPUT_RANGE ", 19)) {
1744 }
else if (!strncmp(
line,
"TITLE", 5)) {
1748 if (
av_sscanf(
line,
"%f %f %f", &lut1d->lut[0][
i], &lut1d->lut[1][
i], &lut1d->lut[2][
i]) != 3)
1762 static const AVOption lut1d_options[] = {
1765 {
"nearest",
"use values from the nearest defined points", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, 0, 0,
TFLAGS,
"interp_mode" },
1766 {
"linear",
"use values from the linear interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, 0, 0,
TFLAGS,
"interp_mode" },
1767 {
"cosine",
"use values from the cosine interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, 0, 0,
TFLAGS,
"interp_mode" },
1768 {
"cubic",
"use values from the cubic interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, 0, 0,
TFLAGS,
"interp_mode" },
1769 {
"spline",
"use values from the spline interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, 0, 0,
TFLAGS,
"interp_mode" },
1775 static inline float interp_1d_nearest(
const LUT1DContext *lut1d,
1776 int idx,
const float s)
1778 return lut1d->lut[idx][
NEAR(
s)];
1781 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1783 static inline float interp_1d_linear(
const LUT1DContext *lut1d,
1784 int idx,
const float s)
1786 const int prev =
PREV(
s);
1787 const int next = NEXT1D(
s);
1788 const float d =
s - prev;
1789 const float p = lut1d->lut[idx][prev];
1790 const float n = lut1d->lut[idx][next];
1795 static inline float interp_1d_cosine(
const LUT1DContext *lut1d,
1796 int idx,
const float s)
1798 const int prev =
PREV(
s);
1799 const int next = NEXT1D(
s);
1800 const float d =
s - prev;
1801 const float p = lut1d->lut[idx][prev];
1802 const float n = lut1d->lut[idx][next];
1803 const float m = (1.f -
cosf(
d *
M_PI)) * .5
f;
1805 return lerpf(p, n, m);
1808 static inline float interp_1d_cubic(
const LUT1DContext *lut1d,
1809 int idx,
const float s)
1811 const int prev =
PREV(
s);
1812 const int next = NEXT1D(
s);
1813 const float mu =
s - prev;
1816 float y0 = lut1d->lut[idx][
FFMAX(prev - 1, 0)];
1817 float y1 = lut1d->lut[idx][prev];
1818 float y2 = lut1d->lut[idx][next];
1819 float y3 = lut1d->lut[idx][
FFMIN(next + 1, lut1d->lutsize - 1)];
1823 a0 = y3 - y2 - y0 + y1;
1828 return a0 * mu * mu2 +
a1 * mu2 +
a2 * mu +
a3;
1831 static inline float interp_1d_spline(
const LUT1DContext *lut1d,
1832 int idx,
const float s)
1834 const int prev =
PREV(
s);
1835 const int next = NEXT1D(
s);
1836 const float x =
s - prev;
1837 float c0,
c1,
c2, c3;
1839 float y0 = lut1d->lut[idx][
FFMAX(prev - 1, 0)];
1840 float y1 = lut1d->lut[idx][prev];
1841 float y2 = lut1d->lut[idx][next];
1842 float y3 = lut1d->lut[idx][
FFMIN(next + 1, lut1d->lutsize - 1)];
1845 c1 = .5f * (y2 - y0);
1846 c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1847 c3 = .5f * (y3 - y0) + 1.5
f * (y1 - y2);
1849 return ((c3 * x +
c2) * x +
c1) * x + c0;
1852 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1853 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1854 void *arg, int jobnr, \
1858 const LUT1DContext *lut1d = ctx->priv; \
1859 const ThreadData *td = arg; \
1860 const AVFrame *in = td->in; \
1861 const AVFrame *out = td->out; \
1862 const int direct = out == in; \
1863 const int slice_start = (in->height * jobnr ) / nb_jobs; \
1864 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1865 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1866 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1867 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1868 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1869 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1870 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1871 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1872 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1873 const float factor = (1 << depth) - 1; \
1874 const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1875 const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1876 const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1878 for (y = slice_start; y < slice_end; y++) { \
1879 uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1880 uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1881 uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1882 uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1883 const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1884 const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1885 const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1886 const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1887 for (x = 0; x < in->width; x++) { \
1888 float r = srcr[x] * scale_r; \
1889 float g = srcg[x] * scale_g; \
1890 float b = srcb[x] * scale_b; \
1891 r = interp_1d_##name(lut1d, 0, r); \
1892 g = interp_1d_##name(lut1d, 1, g); \
1893 b = interp_1d_##name(lut1d, 2, b); \
1894 dstr[x] = av_clip_uintp2(r * factor, depth); \
1895 dstg[x] = av_clip_uintp2(g * factor, depth); \
1896 dstb[x] = av_clip_uintp2(b * factor, depth); \
1897 if (!direct && in->linesize[3]) \
1898 dsta[x] = srca[x]; \
1900 grow += out->linesize[0]; \
1901 brow += out->linesize[1]; \
1902 rrow += out->linesize[2]; \
1903 arow += out->linesize[3]; \
1904 srcgrow += in->linesize[0]; \
1905 srcbrow += in->linesize[1]; \
1906 srcrrow += in->linesize[2]; \
1907 srcarow += in->linesize[3]; \
1912 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1913 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 8, 8)
1914 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1915 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1916 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1918 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1919 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 9)
1920 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1921 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1922 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1924 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1925 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 10)
1926 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1927 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1928 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1930 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1931 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 12)
1932 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1933 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1934 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1936 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1937 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 14)
1938 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1939 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1940 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1942 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1943 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 16)
1944 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1945 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1946 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1948 #define DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(name, depth) \
1949 static int interp_1d_##name##_pf##depth(AVFilterContext *ctx, \
1950 void *arg, int jobnr, \
1954 const LUT1DContext *lut1d = ctx->priv; \
1955 const ThreadData *td = arg; \
1956 const AVFrame *in = td->in; \
1957 const AVFrame *out = td->out; \
1958 const int direct = out == in; \
1959 const int slice_start = (in->height * jobnr ) / nb_jobs; \
1960 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1961 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1962 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1963 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1964 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1965 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1966 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1967 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1968 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1969 const float lutsize = lut1d->lutsize - 1; \
1970 const float scale_r = lut1d->scale.r * lutsize; \
1971 const float scale_g = lut1d->scale.g * lutsize; \
1972 const float scale_b = lut1d->scale.b * lutsize; \
1974 for (y = slice_start; y < slice_end; y++) { \
1975 float *dstg = (float *)grow; \
1976 float *dstb = (float *)brow; \
1977 float *dstr = (float *)rrow; \
1978 float *dsta = (float *)arow; \
1979 const float *srcg = (const float *)srcgrow; \
1980 const float *srcb = (const float *)srcbrow; \
1981 const float *srcr = (const float *)srcrrow; \
1982 const float *srca = (const float *)srcarow; \
1983 for (x = 0; x < in->width; x++) { \
1984 float r = av_clipf(sanitizef(srcr[x]) * scale_r, 0.0f, lutsize); \
1985 float g = av_clipf(sanitizef(srcg[x]) * scale_g, 0.0f, lutsize); \
1986 float b = av_clipf(sanitizef(srcb[x]) * scale_b, 0.0f, lutsize); \
1987 r = interp_1d_##name(lut1d, 0, r); \
1988 g = interp_1d_##name(lut1d, 1, g); \
1989 b = interp_1d_##name(lut1d, 2, b); \
1993 if (!direct && in->linesize[3]) \
1994 dsta[x] = srca[x]; \
1996 grow += out->linesize[0]; \
1997 brow += out->linesize[1]; \
1998 rrow += out->linesize[2]; \
1999 arow += out->linesize[3]; \
2000 srcgrow += in->linesize[0]; \
2001 srcbrow += in->linesize[1]; \
2002 srcrrow += in->linesize[2]; \
2003 srcarow += in->linesize[3]; \
2008 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(nearest, 32)
2009 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(
linear, 32)
2010 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cosine, 32)
2011 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cubic, 32)
2012 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(spline, 32)
2014 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
2015 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
2016 int jobnr, int nb_jobs) \
2019 const LUT1DContext *lut1d = ctx->priv; \
2020 const ThreadData *td = arg; \
2021 const AVFrame *in = td->in; \
2022 const AVFrame *out = td->out; \
2023 const int direct = out == in; \
2024 const int step = lut1d->step; \
2025 const uint8_t r = lut1d->rgba_map[R]; \
2026 const uint8_t g = lut1d->rgba_map[G]; \
2027 const uint8_t b = lut1d->rgba_map[B]; \
2028 const uint8_t a = lut1d->rgba_map[A]; \
2029 const int slice_start = (in->height * jobnr ) / nb_jobs; \
2030 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
2031 uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
2032 const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
2033 const float factor = (1 << nbits) - 1; \
2034 const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
2035 const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
2036 const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
2038 for (y = slice_start; y < slice_end; y++) { \
2039 uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
2040 const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
2041 for (x = 0; x < in->width * step; x += step) { \
2042 float rr = src[x + r] * scale_r; \
2043 float gg = src[x + g] * scale_g; \
2044 float bb = src[x + b] * scale_b; \
2045 rr = interp_1d_##name(lut1d, 0, rr); \
2046 gg = interp_1d_##name(lut1d, 1, gg); \
2047 bb = interp_1d_##name(lut1d, 2, bb); \
2048 dst[x + r] = av_clip_uint##nbits(rr * factor); \
2049 dst[x + g] = av_clip_uint##nbits(gg * factor); \
2050 dst[x + b] = av_clip_uint##nbits(bb * factor); \
2051 if (!direct && step == 4) \
2052 dst[x + a] = src[x + a]; \
2054 dstrow += out->linesize[0]; \
2055 srcrow += in ->linesize[0]; \
2060 DEFINE_INTERP_FUNC_1D(nearest, 8)
2061 DEFINE_INTERP_FUNC_1D(
linear, 8)
2062 DEFINE_INTERP_FUNC_1D(cosine, 8)
2063 DEFINE_INTERP_FUNC_1D(cubic, 8)
2064 DEFINE_INTERP_FUNC_1D(spline, 8)
2066 DEFINE_INTERP_FUNC_1D(nearest, 16)
2067 DEFINE_INTERP_FUNC_1D(
linear, 16)
2068 DEFINE_INTERP_FUNC_1D(cosine, 16)
2069 DEFINE_INTERP_FUNC_1D(cubic, 16)
2070 DEFINE_INTERP_FUNC_1D(spline, 16)
2074 int depth, is16bit, isfloat,
planar;
2075 LUT1DContext *lut1d =
inlink->dst->priv;
2078 depth =
desc->comp[0].depth;
2079 is16bit =
desc->comp[0].depth > 8;
2085 #define SET_FUNC_1D(name) do { \
2086 if (planar && !isfloat) { \
2088 case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
2089 case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
2090 case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
2091 case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
2092 case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
2093 case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
2095 } else if (isfloat) { lut1d->interp = interp_1d_##name##_pf32; \
2096 } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
2097 } else { lut1d->interp = interp_1d_8_##name; } \
2100 switch (lut1d->interpolation) {
2101 case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest);
break;
2102 case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(
linear);
break;
2103 case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine);
break;
2104 case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic);
break;
2105 case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline);
break;
2118 LUT1DContext *lut1d =
ctx->priv;
2120 lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
2123 set_identity_matrix_1d(lut1d, 32);
2134 ext = strrchr(lut1d->file,
'.');
2145 ret = parse_cinespace_1d(
ctx,
f);
2151 if (!
ret && !lut1d->lutsize) {
2164 LUT1DContext *lut1d =
ctx->priv;
2200 static int lut1d_process_command(
AVFilterContext *
ctx,
const char *cmd,
const char *args,
2201 char *res,
int res_len,
int flags)
2203 LUT1DContext *lut1d =
ctx->priv;
2212 set_identity_matrix_1d(lut1d, 32);
2215 return config_input_1d(
ctx->inputs[0]);
2222 .filter_frame = filter_frame_1d,
2223 .config_props = config_input_1d,
2237 .priv_size =
sizeof(LUT1DContext),
2242 .priv_class = &lut1d_class,
2244 .process_command = lut1d_process_command,
static AVFrame * apply_lut(AVFilterLink *inlink, AVFrame *in)
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
static int config_input(AVFilterLink *inlink)
#define AV_PIX_FMT_GBRAP16
#define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth)
static float lerpf(float v0, float v1, float f)
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
#define AV_LOG_WARNING
Something somehow does not look correct.
AVPixelFormat
Pixel format.
static int mix(int c0, int c1)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
static int parse_m3d(AVFilterContext *ctx, FILE *f)
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
#define NEXT_FLOAT_OR_GOTO(value, label)
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
int() avfilter_action_func(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
A function pointer passed to the AVFilterGraph::execute callback to be executed multiple times,...
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
static struct rgbvec apply_prelut(const Lut3DPreLut *prelut, const struct rgbvec *s)
static struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
#define FILTER_PIXFMTS_ARRAY(array)
static int parse_dat(AVFilterContext *ctx, FILE *f)
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
#define AV_PIX_FMT_FLAG_FLOAT
The pixel format contains IEEE-754 floating point values.
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
This structure describes decoded (raw) audio or video data.
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about which is also called distortion Distortion can be quantified by almost any quality measurement one chooses the sum of squared differences is used but more complex methods that consider psychovisual effects can be used as well It makes no difference in this discussion First step
static int skip_line(const char *p)
static int linear(InterplayACMContext *s, unsigned ind, unsigned col)
static struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d, const struct rgbvec *s)
Tetrahedral interpolation.
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
static av_cold int preinit(AVFilterContext *ctx)
static struct rgbvec interp_prism(const LUT3DContext *lut3d, const struct rgbvec *s)
const char * name
Filter name.
#define AVFILTER_DEFINE_CLASS_EXT(name, desc, options)
static int parse_cube(AVFilterContext *ctx, FILE *f)
A link between two filters.
const AVFilter ff_vf_lut3d
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
static int parse_3dl(AVFilterContext *ctx, FILE *f)
#define AV_PIX_FMT_GBRP14
@ AV_PIX_FMT_GBRAP
planar GBRA 4:4:4:4 32bpp
#define AV_PIX_FMT_GBRP10
static double val(void *priv, double ch)
static av_always_inline float scale(float x, float s)
static struct rgbvec interp_trilinear(const LUT3DContext *lut3d, const struct rgbvec *s)
Interpolate using the 8 vertices of a cube.
A filter pad used for either input or output.
static enum AVPixelFormat pix_fmts[]
static int config_output(AVFilterLink *outlink)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
FILE * av_fopen_utf8(const char *path, const char *mode)
Open a file using a UTF-8 filename.
#define AV_PIX_FMT_GBRAP10
#define AV_PIX_FMT_GBRAP12
#define av_assert0(cond)
assert() equivalent, that is always enabled.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
static char * fget_next_word(char *dst, int max, FILE *f)
#define DEFINE_INTERP_FUNC(name, nbits)
#define FILTER_INPUTS(array)
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
#define AV_PIX_FMT_GBRP16
#define AV_PIX_FMT_RGBA64
int av_sscanf(const char *string, const char *format,...)
See libc sscanf manual for more information.
static float prelut_interp_1d_linear(const Lut3DPreLut *prelut, int idx, const float s)
Describe the class of an AVClass context structure.
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
#define fs(width, name, subs,...)
filter_frame For filters that do not use the activate() callback
#define FRAMESYNC_DEFINE_CLASS_EXT(name, context, field, options)
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
Return the number of bits per pixel for the pixel format described by pixdesc, including any padding ...
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
#define AV_PIX_FMT_GBRPF32
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
AVFilterContext * src
source filter
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
static int set_identity_matrix(AVFilterContext *ctx, int size)
static int interpolation(DeclickChannel *c, const double *src, int ar_order, double *acoefficients, int *index, int nb_errors, double *auxiliary, double *interpolated)
#define AV_LOG_INFO
Standard information.
#define AVFILTER_DEFINE_CLASS(fname)
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
#define AV_PIX_FMT_BGRA64
#define i(width, name, range_min, range_max)
avfilter_action_func * interp
int w
agreed upon image width
#define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth)
#define AV_PIX_FMT_GBRP12
#define av_malloc_array(a, b)
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Used for passing data between threads.
@ INTERPOLATE_TETRAHEDRAL
static struct rgbvec interp_pyramid(const LUT3DContext *lut3d, const struct rgbvec *s)
const char * name
Pad name.
static int parse_cinespace(AVFilterContext *ctx, FILE *f)
static float sanitizef(float f)
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
static int allocate_3dlut(AVFilterContext *ctx, int lutsize, int prelut)
#define NEXT_LINE_OR_GOTO(loop_cond, label)
const AVFilter ff_vf_haldclut
int h
agreed upon image height
#define AV_PIX_FMT_GBRAPF32
static struct rgbvec interp_nearest(const LUT3DContext *lut3d, const struct rgbvec *s)
Get the nearest defined point.
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
#define NEXT_LINE(loop_cond)
@ AV_PIX_FMT_GBRP
planar GBR 4:4:4 24bpp
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
#define FILTER_OUTPUTS(array)
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
void ff_lut3d_init_x86(LUT3DContext *s, const AVPixFmtDescriptor *desc)
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
#define flags(name, subs,...)
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
static av_cold int uninit(AVCodecContext *avctx)
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
const AVFilter ff_vf_lut1d
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
uint8_t pi<< 24) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8,(uint64_t)((*(const uint8_t *) pi - 0x80U))<< 56) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16,(*(const int16_t *) pi >>8)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t *) pi *(1<< 16)) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16,(uint64_t)(*(const int16_t *) pi)<< 48) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32,(*(const int32_t *) pi >>24)+0x80) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32,(uint64_t)(*(const int32_t *) pi)<< 32) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S64,(*(const int64_t *) pi >>56)+0x80) CONV_FUNC(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S64, *(const int64_t *) pi *(1.0f/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S64, *(const int64_t *) pi *(1.0/(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float *) pi *(UINT64_C(1)<< 63))) CONV_FUNC(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double *) pi *(UINT64_C(1)<< 63))) #define FMT_PAIR_FUNC(out, in) static conv_func_type *const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB *AV_SAMPLE_FMT_NB]={ FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64), };static void cpy1(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, len);} static void cpy2(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, 2 *len);} static void cpy4(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, 4 *len);} static void cpy8(uint8_t **dst, const uint8_t **src, int len){ memcpy(*dst, *src, 8 *len);} AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, const int *ch_map, int flags) { AudioConvert *ctx;conv_func_type *f=fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt)+AV_SAMPLE_FMT_NB *av_get_packed_sample_fmt(in_fmt)];if(!f) return NULL;ctx=av_mallocz(sizeof(*ctx));if(!ctx) return NULL;if(channels==1){ in_fmt=av_get_planar_sample_fmt(in_fmt);out_fmt=av_get_planar_sample_fmt(out_fmt);} ctx->channels=channels;ctx->conv_f=f;ctx->ch_map=ch_map;if(in_fmt==AV_SAMPLE_FMT_U8||in_fmt==AV_SAMPLE_FMT_U8P) memset(ctx->silence, 0x80, sizeof(ctx->silence));if(out_fmt==in_fmt &&!ch_map) { switch(av_get_bytes_per_sample(in_fmt)){ case 1:ctx->simd_f=cpy1;break;case 2:ctx->simd_f=cpy2;break;case 4:ctx->simd_f=cpy4;break;case 8:ctx->simd_f=cpy8;break;} } if(HAVE_X86ASM &&1) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);return ctx;} void swri_audio_convert_free(AudioConvert **ctx) { av_freep(ctx);} int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) { int ch;int off=0;const int os=(out->planar ? 1 :out->ch_count) *out->bps;unsigned misaligned=0;av_assert0(ctx->channels==out->ch_count);if(ctx->in_simd_align_mask) { int planes=in->planar ? in->ch_count :1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) in->ch[ch];misaligned|=m &ctx->in_simd_align_mask;} if(ctx->out_simd_align_mask) { int planes=out->planar ? out->ch_count :1;unsigned m=0;for(ch=0;ch< planes;ch++) m|=(intptr_t) out->ch[ch];misaligned|=m &ctx->out_simd_align_mask;} if(ctx->simd_f &&!ctx->ch_map &&!misaligned){ off=len &~15;av_assert1(off >=0);av_assert1(off<=len);av_assert2(ctx->channels==SWR_CH_MAX||!in->ch[ctx->channels]);if(off >0){ if(out->planar==in->planar){ int planes=out->planar ? out->ch_count :1;for(ch=0;ch< planes;ch++){ ctx->simd_f(out->ch+ch,(const uint8_t **) in->ch+ch, off *(out-> planar
int interpolation
interp_mode
static int nearest_sample_index(float *data, float x, int low, int hi)