Go to the documentation of this file.
62 #define PRELUT_SIZE 65536
84 #if CONFIG_HALDCLUT_FILTER
99 #define OFFSET(x) offsetof(LUT3DContext, x)
100 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
101 #define COMMON_OPTIONS \
102 { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, FLAGS, "interp_mode" }, \
103 { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
104 { "trilinear", "interpolate values using the 8 points defining a cube", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TRILINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
105 { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
108 #define EXPONENT_MASK 0x7F800000
109 #define MANTISSA_MASK 0x007FFFFF
110 #define SIGN_MASK 0x7FFFFFFF
132 static inline float lerpf(
float v0,
float v1,
float f)
134 return v0 + (v1 -
v0) *
f;
145 #define NEAR(x) ((int)((x) + .5))
146 #define PREV(x) ((int)(x))
147 #define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
155 return lut3d->lut[
NEAR(
s->r) * lut3d->lutsize2 +
NEAR(
s->g) * lut3d->lutsize +
NEAR(
s->b)];
165 const int lutsize2 = lut3d->lutsize2;
166 const int lutsize = lut3d->lutsize;
169 const struct rgbvec d = {
s->r - prev[0],
s->g - prev[1],
s->b - prev[2]};
170 const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
171 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
172 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
173 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
174 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
175 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
176 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
177 const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
195 const int lutsize2 = lut3d->lutsize2;
196 const int lutsize = lut3d->lutsize;
199 const struct rgbvec d = {
s->r - prev[0],
s->g - prev[1],
s->b - prev[2]};
200 const struct rgbvec c000 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + prev[2]];
201 const struct rgbvec c111 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + next[2]];
205 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
206 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
207 c.r = (1-d.
r) * c000.
r + (d.
r-d.
g) * c100.
r + (d.
g-d.
b) * c110.
r + (d.
b) * c111.
r;
208 c.g = (1-d.
r) * c000.
g + (d.
r-d.
g) * c100.
g + (d.
g-d.
b) * c110.
g + (d.
b) * c111.
g;
209 c.b = (1-d.
r) * c000.
b + (d.
r-d.
g) * c100.
b + (d.
g-d.
b) * c110.
b + (d.
b) * c111.
b;
210 }
else if (d.
r > d.
b) {
211 const struct rgbvec c100 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + prev[2]];
212 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
213 c.r = (1-d.
r) * c000.
r + (d.
r-d.
b) * c100.
r + (d.
b-d.
g) * c101.
r + (d.
g) * c111.
r;
214 c.g = (1-d.
r) * c000.
g + (d.
r-d.
b) * c100.
g + (d.
b-d.
g) * c101.
g + (d.
g) * c111.
g;
215 c.b = (1-d.
r) * c000.
b + (d.
r-d.
b) * c100.
b + (d.
b-d.
g) * c101.
b + (d.
g) * c111.
b;
217 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
218 const struct rgbvec c101 = lut3d->lut[next[0] * lutsize2 + prev[1] * lutsize + next[2]];
219 c.r = (1-d.
b) * c000.
r + (d.
b-d.
r) * c001.
r + (d.
r-d.
g) * c101.
r + (d.
g) * c111.
r;
220 c.g = (1-d.
b) * c000.
g + (d.
b-d.
r) * c001.
g + (d.
r-d.
g) * c101.
g + (d.
g) * c111.
g;
221 c.b = (1-d.
b) * c000.
b + (d.
b-d.
r) * c001.
b + (d.
r-d.
g) * c101.
b + (d.
g) * c111.
b;
225 const struct rgbvec c001 = lut3d->lut[prev[0] * lutsize2 + prev[1] * lutsize + next[2]];
226 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
227 c.r = (1-d.
b) * c000.
r + (d.
b-d.
g) * c001.
r + (d.
g-d.
r) * c011.
r + (d.
r) * c111.
r;
228 c.g = (1-d.
b) * c000.
g + (d.
b-d.
g) * c001.
g + (d.
g-d.
r) * c011.
g + (d.
r) * c111.
g;
229 c.b = (1-d.
b) * c000.
b + (d.
b-d.
g) * c001.
b + (d.
g-d.
r) * c011.
b + (d.
r) * c111.
b;
230 }
else if (d.
b > d.
r) {
231 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
232 const struct rgbvec c011 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + next[2]];
233 c.r = (1-d.
g) * c000.
r + (d.
g-d.
b) * c010.
r + (d.
b-d.
r) * c011.
r + (d.
r) * c111.
r;
234 c.g = (1-d.
g) * c000.
g + (d.
g-d.
b) * c010.
g + (d.
b-d.
r) * c011.
g + (d.
r) * c111.
g;
235 c.b = (1-d.
g) * c000.
b + (d.
g-d.
b) * c010.
b + (d.
b-d.
r) * c011.
b + (d.
r) * c111.
b;
237 const struct rgbvec c010 = lut3d->lut[prev[0] * lutsize2 + next[1] * lutsize + prev[2]];
238 const struct rgbvec c110 = lut3d->lut[next[0] * lutsize2 + next[1] * lutsize + prev[2]];
239 c.r = (1-d.
g) * c000.
r + (d.
g-d.
r) * c010.
r + (d.
r-d.
b) * c110.
r + (d.
b) * c111.
r;
240 c.g = (1-d.
g) * c000.
g + (d.
g-d.
r) * c010.
g + (d.
r-d.
b) * c110.
g + (d.
b) * c111.
g;
241 c.b = (1-d.
g) * c000.
b + (d.
g-d.
r) * c010.
b + (d.
r-d.
b) * c110.
b + (d.
b) * c111.
b;
248 int idx,
const float s)
250 const int lut_max = prelut->
size - 1;
251 const float scaled = (
s - prelut->
min[idx]) * prelut->
scale[idx];
252 const float x = av_clipf(scaled, 0.0
f, lut_max);
253 const int prev =
PREV(x);
254 const int next =
FFMIN((
int)(x) + 1, lut_max);
255 const float p = prelut->
lut[idx][prev];
256 const float n = prelut->
lut[idx][next];
257 const float d = x - (float)prev;
258 return lerpf(p, n, d);
266 if (prelut->size <= 0)
275 #define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \
276 static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
279 const LUT3DContext *lut3d = ctx->priv; \
280 const Lut3DPreLut *prelut = &lut3d->prelut; \
281 const ThreadData *td = arg; \
282 const AVFrame *in = td->in; \
283 const AVFrame *out = td->out; \
284 const int direct = out == in; \
285 const int slice_start = (in->height * jobnr ) / nb_jobs; \
286 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
287 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
288 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
289 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
290 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
291 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
292 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
293 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
294 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
295 const float lut_max = lut3d->lutsize - 1; \
296 const float scale_f = 1.0f / ((1<<depth) - 1); \
297 const float scale_r = lut3d->scale.r * lut_max; \
298 const float scale_g = lut3d->scale.g * lut_max; \
299 const float scale_b = lut3d->scale.b * lut_max; \
301 for (y = slice_start; y < slice_end; y++) { \
302 uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
303 uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
304 uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
305 uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
306 const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
307 const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
308 const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
309 const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
310 for (x = 0; x < in->width; x++) { \
311 const struct rgbvec rgb = {srcr[x] * scale_f, \
313 srcb[x] * scale_f}; \
314 const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
315 const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
316 av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
317 av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
318 struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
319 dstr[x] = av_clip_uintp2(vec.r * (float)((1<<depth) - 1), depth); \
320 dstg[x] = av_clip_uintp2(vec.g * (float)((1<<depth) - 1), depth); \
321 dstb[x] = av_clip_uintp2(vec.b * (float)((1<<depth) - 1), depth); \
322 if (!direct && in->linesize[3]) \
325 grow += out->linesize[0]; \
326 brow += out->linesize[1]; \
327 rrow += out->linesize[2]; \
328 arow += out->linesize[3]; \
329 srcgrow += in->linesize[0]; \
330 srcbrow += in->linesize[1]; \
331 srcrrow += in->linesize[2]; \
332 srcarow += in->linesize[3]; \
361 #define DEFINE_INTERP_FUNC_PLANAR_FLOAT(name, depth) \
362 static int interp_##name##_pf##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
365 const LUT3DContext *lut3d = ctx->priv; \
366 const Lut3DPreLut *prelut = &lut3d->prelut; \
367 const ThreadData *td = arg; \
368 const AVFrame *in = td->in; \
369 const AVFrame *out = td->out; \
370 const int direct = out == in; \
371 const int slice_start = (in->height * jobnr ) / nb_jobs; \
372 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
373 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
374 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
375 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
376 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
377 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
378 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
379 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
380 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
381 const float lut_max = lut3d->lutsize - 1; \
382 const float scale_r = lut3d->scale.r * lut_max; \
383 const float scale_g = lut3d->scale.g * lut_max; \
384 const float scale_b = lut3d->scale.b * lut_max; \
386 for (y = slice_start; y < slice_end; y++) { \
387 float *dstg = (float *)grow; \
388 float *dstb = (float *)brow; \
389 float *dstr = (float *)rrow; \
390 float *dsta = (float *)arow; \
391 const float *srcg = (const float *)srcgrow; \
392 const float *srcb = (const float *)srcbrow; \
393 const float *srcr = (const float *)srcrrow; \
394 const float *srca = (const float *)srcarow; \
395 for (x = 0; x < in->width; x++) { \
396 const struct rgbvec rgb = {sanitizef(srcr[x]), \
397 sanitizef(srcg[x]), \
398 sanitizef(srcb[x])}; \
399 const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
400 const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
401 av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
402 av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
403 struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
407 if (!direct && in->linesize[3]) \
410 grow += out->linesize[0]; \
411 brow += out->linesize[1]; \
412 rrow += out->linesize[2]; \
413 arow += out->linesize[3]; \
414 srcgrow += in->linesize[0]; \
415 srcbrow += in->linesize[1]; \
416 srcrrow += in->linesize[2]; \
417 srcarow += in->linesize[3]; \
426 #define DEFINE_INTERP_FUNC(name, nbits) \
427 static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
430 const LUT3DContext *lut3d = ctx->priv; \
431 const Lut3DPreLut *prelut = &lut3d->prelut; \
432 const ThreadData *td = arg; \
433 const AVFrame *in = td->in; \
434 const AVFrame *out = td->out; \
435 const int direct = out == in; \
436 const int step = lut3d->step; \
437 const uint8_t r = lut3d->rgba_map[R]; \
438 const uint8_t g = lut3d->rgba_map[G]; \
439 const uint8_t b = lut3d->rgba_map[B]; \
440 const uint8_t a = lut3d->rgba_map[A]; \
441 const int slice_start = (in->height * jobnr ) / nb_jobs; \
442 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
443 uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
444 const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
445 const float lut_max = lut3d->lutsize - 1; \
446 const float scale_f = 1.0f / ((1<<nbits) - 1); \
447 const float scale_r = lut3d->scale.r * lut_max; \
448 const float scale_g = lut3d->scale.g * lut_max; \
449 const float scale_b = lut3d->scale.b * lut_max; \
451 for (y = slice_start; y < slice_end; y++) { \
452 uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
453 const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
454 for (x = 0; x < in->width * step; x += step) { \
455 const struct rgbvec rgb = {src[x + r] * scale_f, \
456 src[x + g] * scale_f, \
457 src[x + b] * scale_f}; \
458 const struct rgbvec prelut_rgb = apply_prelut(prelut, &rgb); \
459 const struct rgbvec scaled_rgb = {av_clipf(prelut_rgb.r * scale_r, 0, lut_max), \
460 av_clipf(prelut_rgb.g * scale_g, 0, lut_max), \
461 av_clipf(prelut_rgb.b * scale_b, 0, lut_max)}; \
462 struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
463 dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
464 dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
465 dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
466 if (!direct && step == 4) \
467 dst[x + a] = src[x + a]; \
469 dstrow += out->linesize[0]; \
470 srcrow += in ->linesize[0]; \
483 #define MAX_LINE_SIZE 512
489 return !*p || *p ==
'#';
500 while ((
c = fgetc(
f)) != EOF) {
511 if ((
c = fgetc(
f)) == EOF)
526 #define NEXT_LINE(loop_cond) do { \
527 if (!fgets(line, sizeof(line), f)) { \
528 av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
529 return AVERROR_INVALIDDATA; \
533 #define NEXT_LINE_OR_GOTO(loop_cond, label) do { \
534 if (!fgets(line, sizeof(line), f)) { \
535 av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
536 ret = AVERROR_INVALIDDATA; \
545 if (lutsize < 2 || lutsize >
MAX_LEVEL) {
557 for (
i = 0;
i < 3;
i++) {
565 for (
i = 0;
i < 3;
i++) {
570 lut3d->
lutsize2 = lutsize * lutsize;
586 if (!strncmp(
line,
"3DLUTSIZE ", 10)) {
596 for (k = 0; k <
size; k++) {
597 for (j = 0; j <
size; j++) {
600 if (k != 0 || j != 0 ||
i != 0)
615 float min[3] = {0.0, 0.0, 0.0};
616 float max[3] = {1.0, 1.0, 1.0};
619 if (!strncmp(
line,
"LUT_3D_SIZE", 11)) {
628 for (k = 0; k <
size; k++) {
629 for (j = 0; j <
size; j++) {
636 if (!strncmp(
line,
"DOMAIN_", 7)) {
638 if (!strncmp(
line + 7,
"MIN ", 4)) vals =
min;
639 else if (!strncmp(
line + 7,
"MAX ", 4)) vals =
max;
646 }
else if (!strncmp(
line,
"TITLE", 5)) {
674 const int size2 = 17 * 17;
675 const float scale = 16*16*16;
684 for (k = 0; k <
size; k++) {
685 for (j = 0; j <
size; j++) {
709 uint8_t rgb_map[3] = {0, 1, 2};
714 else if (!strncmp(
line,
"values", 6)) {
715 const char *p =
line + 6;
716 #define SET_COLOR(id) do { \
717 while (av_isspace(*p)) \
720 case 'r': rgb_map[id] = 0; break; \
721 case 'g': rgb_map[id] = 1; break; \
722 case 'b': rgb_map[id] = 2; break; \
724 while (*p && !av_isspace(*p)) \
734 if (
in == -1 ||
out == -1) {
738 if (
in < 2 ||
out < 2 ||
752 scale = 1. / (
out - 1);
754 for (k = 0; k <
size; k++) {
755 for (j = 0; j <
size; j++) {
763 vec->
r =
val[rgb_map[0]] * scale;
764 vec->
g =
val[rgb_map[1]] * scale;
765 vec->
b =
val[rgb_map[2]] * scale;
789 mid = (low + hi) / 2;
800 #define NEXT_FLOAT_OR_GOTO(value, label) \
801 if (!fget_next_word(line, sizeof(line) ,f)) { \
802 ret = AVERROR_INVALIDDATA; \
805 if (av_sscanf(line, "%f", &value) != 1) { \
806 ret = AVERROR_INVALIDDATA; \
814 float in_min[3] = {0.0, 0.0, 0.0};
815 float in_max[3] = {1.0, 1.0, 1.0};
816 float out_min[3] = {0.0, 0.0, 0.0};
817 float out_max[3] = {1.0, 1.0, 1.0};
818 int inside_metadata = 0,
size, size2;
822 int prelut_sizes[3] = {0, 0, 0};
827 if (strncmp(
line,
"CSPLUTV100", 10)) {
834 if (strncmp(
line,
"3D", 2)) {
843 if (!strncmp(
line,
"BEGIN METADATA", 14)) {
847 if (!strncmp(
line,
"END METADATA", 12)) {
851 if (inside_metadata == 0) {
852 int size_r, size_g, size_b;
854 for (
int i = 0;
i < 3;
i++) {
855 int npoints = strtol(
line,
NULL, 0);
866 if (in_prelut[
i] || out_prelut[
i]) {
872 in_prelut[
i] = (
float*)
av_malloc(npoints *
sizeof(
float));
873 out_prelut[
i] = (
float*)
av_malloc(npoints *
sizeof(
float));
874 if (!in_prelut[
i] || !out_prelut[
i]) {
879 prelut_sizes[
i] = npoints;
882 out_min[
i] = FLT_MAX;
883 out_max[
i] = FLT_MIN;
887 for (
int j = 0; j < npoints; j++) {
889 in_min[
i] =
FFMIN(in_min[
i], v);
890 in_max[
i] =
FFMAX(in_max[
i], v);
900 for (
int j = 0; j < npoints; j++) {
902 out_min[
i] =
FFMIN(out_min[
i], v);
903 out_max[
i] =
FFMAX(out_max[
i], v);
904 out_prelut[
i][j] = v;
907 }
else if (npoints == 2) {
928 if (
av_sscanf(
line,
"%d %d %d", &size_r, &size_g, &size_b) != 3) {
932 if (size_r != size_g || size_r != size_b) {
941 if (prelut_sizes[0] && prelut_sizes[1] && prelut_sizes[2])
948 for (
int k = 0; k <
size; k++) {
949 for (
int j = 0; j <
size; j++) {
950 for (
int i = 0;
i <
size;
i++) {
959 vec->
r *= out_max[0] - out_min[0];
960 vec->
g *= out_max[1] - out_min[1];
961 vec->
b *= out_max[2] - out_min[2];
971 for (
int c = 0;
c < 3;
c++) {
984 a = out_prelut[
c][idx + 0];
985 b = out_prelut[
c][idx + 1];
986 mix = x - in_prelut[
c][idx];
996 lut3d->
scale.
r = av_clipf(1. / (in_max[0] - in_min[0]), 0.
f, 1.
f);
997 lut3d->
scale.
g = av_clipf(1. / (in_max[1] - in_min[1]), 0.
f, 1.
f);
998 lut3d->
scale.
b = av_clipf(1. / (in_max[2] - in_min[2]), 0.
f, 1.
f);
1002 for (
int c = 0;
c < 3;
c++) {
1014 const float c = 1. / (
size - 1);
1020 for (k = 0; k <
size; k++) {
1021 for (j = 0; j <
size; j++) {
1061 int depth, is16bit, isfloat,
planar;
1065 depth =
desc->comp[0].depth;
1066 is16bit =
desc->comp[0].depth > 8;
1072 #define SET_FUNC(name) do { \
1073 if (planar && !isfloat) { \
1075 case 8: lut3d->interp = interp_8_##name##_p8; break; \
1076 case 9: lut3d->interp = interp_16_##name##_p9; break; \
1077 case 10: lut3d->interp = interp_16_##name##_p10; break; \
1078 case 12: lut3d->interp = interp_16_##name##_p12; break; \
1079 case 14: lut3d->interp = interp_16_##name##_p14; break; \
1080 case 16: lut3d->interp = interp_16_##name##_p16; break; \
1082 } else if (isfloat) { lut3d->interp = interp_##name##_pf32; \
1083 } else if (is16bit) { lut3d->interp = interp_16_##name; \
1084 } else { lut3d->interp = interp_8_##name; } \
1136 #if CONFIG_LUT3D_FILTER
1137 static const AVOption lut3d_options[] = {
1164 ext = strrchr(lut3d->
file,
'.');
1203 for (
i = 0;
i < 3;
i++) {
1235 .priv_class = &lut3d_class,
1240 #if CONFIG_HALDCLUT_FILTER
1245 const int linesize =
frame->linesize[0];
1246 const int w = lut3d->clut_width;
1247 const int step = lut3d->clut_step;
1248 const uint8_t *rgba_map = lut3d->clut_rgba_map;
1250 const int level2 = lut3d->
lutsize2;
1252 #define LOAD_CLUT(nbits) do { \
1253 int i, j, k, x = 0, y = 0; \
1255 for (k = 0; k < level; k++) { \
1256 for (j = 0; j < level; j++) { \
1257 for (i = 0; i < level; i++) { \
1258 const uint##nbits##_t *src = (const uint##nbits##_t *) \
1259 (data + y*linesize + x*step); \
1260 struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1261 vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
1262 vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
1263 vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
1273 switch (lut3d->clut_bits) {
1274 case 8: LOAD_CLUT(8);
break;
1275 case 16: LOAD_CLUT(16);
break;
1284 const int glinesize =
frame->linesize[0];
1285 const int blinesize =
frame->linesize[1];
1286 const int rlinesize =
frame->linesize[2];
1287 const int w = lut3d->clut_width;
1289 const int level2 = lut3d->
lutsize2;
1291 #define LOAD_CLUT_PLANAR(nbits, depth) do { \
1292 int i, j, k, x = 0, y = 0; \
1294 for (k = 0; k < level; k++) { \
1295 for (j = 0; j < level; j++) { \
1296 for (i = 0; i < level; i++) { \
1297 const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \
1298 (datag + y*glinesize); \
1299 const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \
1300 (datab + y*blinesize); \
1301 const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \
1302 (datar + y*rlinesize); \
1303 struct rgbvec *vec = &lut3d->lut[i * level2 + j * level + k]; \
1304 vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \
1305 vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \
1306 vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \
1316 switch (lut3d->clut_bits) {
1317 case 8: LOAD_CLUT_PLANAR(8, 8);
break;
1318 case 9: LOAD_CLUT_PLANAR(16, 9);
break;
1319 case 10: LOAD_CLUT_PLANAR(16, 10);
break;
1320 case 12: LOAD_CLUT_PLANAR(16, 12);
break;
1321 case 14: LOAD_CLUT_PLANAR(16, 14);
break;
1322 case 16: LOAD_CLUT_PLANAR(16, 16);
break;
1331 const int glinesize =
frame->linesize[0];
1332 const int blinesize =
frame->linesize[1];
1333 const int rlinesize =
frame->linesize[2];
1334 const int w = lut3d->clut_width;
1336 const int level2 = lut3d->
lutsize2;
1338 int i, j, k, x = 0, y = 0;
1340 for (k = 0; k <
level; k++) {
1341 for (j = 0; j <
level; j++) {
1343 const float *gsrc = (
const float *)(datag + y*glinesize);
1344 const float *bsrc = (
const float *)(datab + y*blinesize);
1345 const float *rsrc = (
const float *)(datar + y*rlinesize);
1368 outlink->
w =
ctx->inputs[0]->w;
1369 outlink->
h =
ctx->inputs[0]->h;
1391 lut3d->clut_bits =
desc->comp[0].depth;
1415 const int max_clut_level = sqrt(
MAX_LEVEL);
1416 const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
1418 "(maximum level is %d, or %dx%d CLUT)\n",
1419 max_clut_level, max_clut_size, max_clut_size);
1439 if (lut3d->clut_float)
1440 update_clut_float(
ctx->priv, second);
1441 else if (lut3d->clut_planar)
1442 update_clut_planar(
ctx->priv, second);
1444 update_clut_packed(
ctx->priv, second);
1453 lut3d->fs.on_event = update_apply_clut;
1464 static const AVOption haldclut_options[] = {
1478 .config_props = config_clut,
1496 .preinit = haldclut_framesync_preinit,
1497 .
init = haldclut_init,
1498 .
uninit = haldclut_uninit,
1501 .
inputs = haldclut_inputs,
1503 .priv_class = &haldclut_class,
1508 #if CONFIG_LUT1D_FILTER
1510 enum interp_1d_mode {
1511 INTERPOLATE_1D_NEAREST,
1512 INTERPOLATE_1D_LINEAR,
1513 INTERPOLATE_1D_CUBIC,
1514 INTERPOLATE_1D_COSINE,
1515 INTERPOLATE_1D_SPLINE,
1519 #define MAX_1D_LEVEL 65536
1521 typedef struct LUT1DContext {
1528 float lut[3][MAX_1D_LEVEL];
1534 #define OFFSET(x) offsetof(LUT1DContext, x)
1536 static void set_identity_matrix_1d(LUT1DContext *lut1d,
int size)
1538 const float c = 1. / (
size - 1);
1541 lut1d->lutsize =
size;
1543 lut1d->lut[0][
i] =
i *
c;
1544 lut1d->lut[1][
i] =
i *
c;
1545 lut1d->lut[2][
i] =
i *
c;
1551 LUT1DContext *lut1d =
ctx->priv;
1553 float in_min[3] = {0.0, 0.0, 0.0};
1554 float in_max[3] = {1.0, 1.0, 1.0};
1555 float out_min[3] = {0.0, 0.0, 0.0};
1556 float out_max[3] = {1.0, 1.0, 1.0};
1557 int inside_metadata = 0,
size;
1560 if (strncmp(
line,
"CSPLUTV100", 10)) {
1566 if (strncmp(
line,
"1D", 2)) {
1574 if (!strncmp(
line,
"BEGIN METADATA", 14)) {
1575 inside_metadata = 1;
1578 if (!strncmp(
line,
"END METADATA", 12)) {
1579 inside_metadata = 0;
1582 if (inside_metadata == 0) {
1583 for (
int i = 0;
i < 3;
i++) {
1584 int npoints = strtol(
line,
NULL, 0);
1602 if (size < 2 || size > MAX_1D_LEVEL) {
1607 lut1d->lutsize =
size;
1609 for (
int i = 0;
i <
size;
i++) {
1611 if (
av_sscanf(
line,
"%f %f %f", &lut1d->lut[0][
i], &lut1d->lut[1][
i], &lut1d->lut[2][
i]) != 3)
1613 lut1d->lut[0][
i] *= out_max[0] - out_min[0];
1614 lut1d->lut[1][
i] *= out_max[1] - out_min[1];
1615 lut1d->lut[2][
i] *= out_max[2] - out_min[2];
1622 lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.
f, 1.
f);
1623 lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.
f, 1.
f);
1624 lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.
f, 1.
f);
1631 LUT1DContext *lut1d =
ctx->priv;
1633 float min[3] = {0.0, 0.0, 0.0};
1634 float max[3] = {1.0, 1.0, 1.0};
1637 if (!strncmp(
line,
"LUT_1D_SIZE", 11)) {
1641 if (size < 2 || size > MAX_1D_LEVEL) {
1645 lut1d->lutsize =
size;
1650 if (!strncmp(
line,
"DOMAIN_", 7)) {
1652 if (!strncmp(
line + 7,
"MIN ", 4)) vals =
min;
1653 else if (!strncmp(
line + 7,
"MAX ", 4)) vals =
max;
1660 }
else if (!strncmp(
line,
"LUT_1D_INPUT_RANGE ", 19)) {
1665 }
else if (!strncmp(
line,
"TITLE", 5)) {
1669 if (
av_sscanf(
line,
"%f %f %f", &lut1d->lut[0][
i], &lut1d->lut[1][
i], &lut1d->lut[2][
i]) != 3)
1676 lut1d->scale.r = av_clipf(1. / (
max[0] -
min[0]), 0.
f, 1.
f);
1677 lut1d->scale.g = av_clipf(1. / (
max[1] -
min[1]), 0.
f, 1.
f);
1678 lut1d->scale.b = av_clipf(1. / (
max[2] -
min[2]), 0.
f, 1.
f);
1683 static const AVOption lut1d_options[] = {
1686 {
"nearest",
"use values from the nearest defined points", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, INT_MIN, INT_MAX,
FLAGS,
"interp_mode" },
1687 {
"linear",
"use values from the linear interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, INT_MIN, INT_MAX,
FLAGS,
"interp_mode" },
1688 {
"cosine",
"use values from the cosine interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, INT_MIN, INT_MAX,
FLAGS,
"interp_mode" },
1689 {
"cubic",
"use values from the cubic interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, INT_MIN, INT_MAX,
FLAGS,
"interp_mode" },
1690 {
"spline",
"use values from the spline interpolation", 0,
AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, INT_MIN, INT_MAX,
FLAGS,
"interp_mode" },
1696 static inline float interp_1d_nearest(
const LUT1DContext *lut1d,
1697 int idx,
const float s)
1699 return lut1d->lut[idx][
NEAR(
s)];
1702 #define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1))
1704 static inline float interp_1d_linear(
const LUT1DContext *lut1d,
1705 int idx,
const float s)
1707 const int prev =
PREV(
s);
1708 const int next = NEXT1D(
s);
1709 const float d =
s - prev;
1710 const float p = lut1d->lut[idx][prev];
1711 const float n = lut1d->lut[idx][next];
1713 return lerpf(p, n, d);
1716 static inline float interp_1d_cosine(
const LUT1DContext *lut1d,
1717 int idx,
const float s)
1719 const int prev =
PREV(
s);
1720 const int next = NEXT1D(
s);
1721 const float d =
s - prev;
1722 const float p = lut1d->lut[idx][prev];
1723 const float n = lut1d->lut[idx][next];
1724 const float m = (1.f -
cosf(d *
M_PI)) * .5
f;
1726 return lerpf(p, n, m);
1729 static inline float interp_1d_cubic(
const LUT1DContext *lut1d,
1730 int idx,
const float s)
1732 const int prev =
PREV(
s);
1733 const int next = NEXT1D(
s);
1734 const float mu =
s - prev;
1737 float y0 = lut1d->lut[idx][
FFMAX(prev - 1, 0)];
1738 float y1 = lut1d->lut[idx][prev];
1739 float y2 = lut1d->lut[idx][next];
1740 float y3 = lut1d->lut[idx][
FFMIN(next + 1, lut1d->lutsize - 1)];
1744 a0 = y3 - y2 - y0 + y1;
1749 return a0 * mu * mu2 +
a1 * mu2 +
a2 * mu +
a3;
1752 static inline float interp_1d_spline(
const LUT1DContext *lut1d,
1753 int idx,
const float s)
1755 const int prev =
PREV(
s);
1756 const int next = NEXT1D(
s);
1757 const float x =
s - prev;
1758 float c0,
c1,
c2, c3;
1760 float y0 = lut1d->lut[idx][
FFMAX(prev - 1, 0)];
1761 float y1 = lut1d->lut[idx][prev];
1762 float y2 = lut1d->lut[idx][next];
1763 float y3 = lut1d->lut[idx][
FFMIN(next + 1, lut1d->lutsize - 1)];
1766 c1 = .5f * (y2 - y0);
1767 c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3;
1768 c3 = .5f * (y3 - y0) + 1.5
f * (y1 - y2);
1770 return ((c3 * x +
c2) * x +
c1) * x + c0;
1773 #define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \
1774 static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \
1775 void *arg, int jobnr, \
1779 const LUT1DContext *lut1d = ctx->priv; \
1780 const ThreadData *td = arg; \
1781 const AVFrame *in = td->in; \
1782 const AVFrame *out = td->out; \
1783 const int direct = out == in; \
1784 const int slice_start = (in->height * jobnr ) / nb_jobs; \
1785 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1786 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1787 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1788 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1789 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1790 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1791 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1792 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1793 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1794 const float factor = (1 << depth) - 1; \
1795 const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1796 const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1797 const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1799 for (y = slice_start; y < slice_end; y++) { \
1800 uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \
1801 uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \
1802 uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \
1803 uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \
1804 const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \
1805 const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \
1806 const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \
1807 const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \
1808 for (x = 0; x < in->width; x++) { \
1809 float r = srcr[x] * scale_r; \
1810 float g = srcg[x] * scale_g; \
1811 float b = srcb[x] * scale_b; \
1812 r = interp_1d_##name(lut1d, 0, r); \
1813 g = interp_1d_##name(lut1d, 1, g); \
1814 b = interp_1d_##name(lut1d, 2, b); \
1815 dstr[x] = av_clip_uintp2(r * factor, depth); \
1816 dstg[x] = av_clip_uintp2(g * factor, depth); \
1817 dstb[x] = av_clip_uintp2(b * factor, depth); \
1818 if (!direct && in->linesize[3]) \
1819 dsta[x] = srca[x]; \
1821 grow += out->linesize[0]; \
1822 brow += out->linesize[1]; \
1823 rrow += out->linesize[2]; \
1824 arow += out->linesize[3]; \
1825 srcgrow += in->linesize[0]; \
1826 srcbrow += in->linesize[1]; \
1827 srcrrow += in->linesize[2]; \
1828 srcarow += in->linesize[3]; \
1833 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8)
1834 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 8, 8)
1835 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8)
1836 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8)
1837 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8)
1839 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9)
1840 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 9)
1841 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9)
1842 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9)
1843 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9)
1845 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10)
1846 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 10)
1847 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10)
1848 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10)
1849 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10)
1851 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12)
1852 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 12)
1853 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12)
1854 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12)
1855 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12)
1857 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14)
1858 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 14)
1859 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14)
1860 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14)
1861 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14)
1863 DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16)
1864 DEFINE_INTERP_FUNC_PLANAR_1D(
linear, 16, 16)
1865 DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16)
1866 DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16)
1867 DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16)
1869 #define DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(name, depth) \
1870 static int interp_1d_##name##_pf##depth(AVFilterContext *ctx, \
1871 void *arg, int jobnr, \
1875 const LUT1DContext *lut1d = ctx->priv; \
1876 const ThreadData *td = arg; \
1877 const AVFrame *in = td->in; \
1878 const AVFrame *out = td->out; \
1879 const int direct = out == in; \
1880 const int slice_start = (in->height * jobnr ) / nb_jobs; \
1881 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1882 uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \
1883 uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \
1884 uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \
1885 uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \
1886 const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \
1887 const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \
1888 const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \
1889 const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \
1890 const float lutsize = lut1d->lutsize - 1; \
1891 const float scale_r = lut1d->scale.r * lutsize; \
1892 const float scale_g = lut1d->scale.g * lutsize; \
1893 const float scale_b = lut1d->scale.b * lutsize; \
1895 for (y = slice_start; y < slice_end; y++) { \
1896 float *dstg = (float *)grow; \
1897 float *dstb = (float *)brow; \
1898 float *dstr = (float *)rrow; \
1899 float *dsta = (float *)arow; \
1900 const float *srcg = (const float *)srcgrow; \
1901 const float *srcb = (const float *)srcbrow; \
1902 const float *srcr = (const float *)srcrrow; \
1903 const float *srca = (const float *)srcarow; \
1904 for (x = 0; x < in->width; x++) { \
1905 float r = av_clipf(sanitizef(srcr[x]) * scale_r, 0.0f, lutsize); \
1906 float g = av_clipf(sanitizef(srcg[x]) * scale_g, 0.0f, lutsize); \
1907 float b = av_clipf(sanitizef(srcb[x]) * scale_b, 0.0f, lutsize); \
1908 r = interp_1d_##name(lut1d, 0, r); \
1909 g = interp_1d_##name(lut1d, 1, g); \
1910 b = interp_1d_##name(lut1d, 2, b); \
1914 if (!direct && in->linesize[3]) \
1915 dsta[x] = srca[x]; \
1917 grow += out->linesize[0]; \
1918 brow += out->linesize[1]; \
1919 rrow += out->linesize[2]; \
1920 arow += out->linesize[3]; \
1921 srcgrow += in->linesize[0]; \
1922 srcbrow += in->linesize[1]; \
1923 srcrrow += in->linesize[2]; \
1924 srcarow += in->linesize[3]; \
1929 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(nearest, 32)
1930 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(
linear, 32)
1931 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cosine, 32)
1932 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(cubic, 32)
1933 DEFINE_INTERP_FUNC_PLANAR_1D_FLOAT(spline, 32)
1935 #define DEFINE_INTERP_FUNC_1D(name, nbits) \
1936 static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \
1937 int jobnr, int nb_jobs) \
1940 const LUT1DContext *lut1d = ctx->priv; \
1941 const ThreadData *td = arg; \
1942 const AVFrame *in = td->in; \
1943 const AVFrame *out = td->out; \
1944 const int direct = out == in; \
1945 const int step = lut1d->step; \
1946 const uint8_t r = lut1d->rgba_map[R]; \
1947 const uint8_t g = lut1d->rgba_map[G]; \
1948 const uint8_t b = lut1d->rgba_map[B]; \
1949 const uint8_t a = lut1d->rgba_map[A]; \
1950 const int slice_start = (in->height * jobnr ) / nb_jobs; \
1951 const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
1952 uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
1953 const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
1954 const float factor = (1 << nbits) - 1; \
1955 const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \
1956 const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \
1957 const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \
1959 for (y = slice_start; y < slice_end; y++) { \
1960 uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
1961 const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
1962 for (x = 0; x < in->width * step; x += step) { \
1963 float rr = src[x + r] * scale_r; \
1964 float gg = src[x + g] * scale_g; \
1965 float bb = src[x + b] * scale_b; \
1966 rr = interp_1d_##name(lut1d, 0, rr); \
1967 gg = interp_1d_##name(lut1d, 1, gg); \
1968 bb = interp_1d_##name(lut1d, 2, bb); \
1969 dst[x + r] = av_clip_uint##nbits(rr * factor); \
1970 dst[x + g] = av_clip_uint##nbits(gg * factor); \
1971 dst[x + b] = av_clip_uint##nbits(bb * factor); \
1972 if (!direct && step == 4) \
1973 dst[x + a] = src[x + a]; \
1975 dstrow += out->linesize[0]; \
1976 srcrow += in ->linesize[0]; \
1981 DEFINE_INTERP_FUNC_1D(nearest, 8)
1982 DEFINE_INTERP_FUNC_1D(
linear, 8)
1983 DEFINE_INTERP_FUNC_1D(cosine, 8)
1984 DEFINE_INTERP_FUNC_1D(cubic, 8)
1985 DEFINE_INTERP_FUNC_1D(spline, 8)
1987 DEFINE_INTERP_FUNC_1D(nearest, 16)
1988 DEFINE_INTERP_FUNC_1D(
linear, 16)
1989 DEFINE_INTERP_FUNC_1D(cosine, 16)
1990 DEFINE_INTERP_FUNC_1D(cubic, 16)
1991 DEFINE_INTERP_FUNC_1D(spline, 16)
1995 int depth, is16bit, isfloat,
planar;
1996 LUT1DContext *lut1d =
inlink->dst->priv;
1999 depth =
desc->comp[0].depth;
2000 is16bit =
desc->comp[0].depth > 8;
2006 #define SET_FUNC_1D(name) do { \
2007 if (planar && !isfloat) { \
2009 case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \
2010 case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \
2011 case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \
2012 case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \
2013 case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \
2014 case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \
2016 } else if (isfloat) { lut1d->interp = interp_1d_##name##_pf32; \
2017 } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \
2018 } else { lut1d->interp = interp_1d_8_##name; } \
2021 switch (lut1d->interpolation) {
2022 case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest);
break;
2023 case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(
linear);
break;
2024 case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine);
break;
2025 case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic);
break;
2026 case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline);
break;
2039 LUT1DContext *lut1d =
ctx->priv;
2041 lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f;
2044 set_identity_matrix_1d(lut1d, 32);
2055 ext = strrchr(lut1d->file,
'.');
2066 ret = parse_cinespace_1d(
ctx,
f);
2072 if (!
ret && !lut1d->lutsize) {
2085 LUT1DContext *lut1d =
ctx->priv;
2124 .filter_frame = filter_frame_1d,
2125 .config_props = config_input_1d,
2141 .priv_size =
sizeof(LUT1DContext),
2146 .priv_class = &lut1d_class,
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 av_cold int init(AVCodecContext *avctx)
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)
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.
static av_cold int end(AVCodecContext *avctx)
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)
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
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...
const char * name
Filter name.
static int parse_cube(AVFilterContext *ctx, FILE *f)
AVFormatInternal * internal
An opaque field for libavformat internal usage.
A link between two filters.
@ INTERPOLATE_TETRAHEDRAL
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 struct rgbvec interp_trilinear(const LUT3DContext *lut3d, const struct rgbvec *s)
Interpolate using the 8 vertices of a cube.
static int config_output(AVFilterLink *outlink)
A filter pad used for either input or output.
#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.
static const AVFilterPad outputs[]
static enum AVPixelFormat pix_fmts[]
#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)
@ 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
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... 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 inputs
@ 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
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_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
#define AVFILTER_DEFINE_CLASS(fname)
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
#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.
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)
static int query_formats(AVFilterContext *ctx)
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...
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
#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.
int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1)
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)