History

avfilter: add colormap video filter

Paul B Mahol committed 4 years ago

Commit 43ea19f1 parent b1b72496 files · +619 −1Browse files

Unified · Split

6 files
  1. Changelog +1 −0
  2. doc/filters.texi +33 −0
  3. libavfilter/Makefile +1 −0
  4. libavfilter/allfilters.c +1 −0
  5. libavfilter/version.h +1 −1
  6. libavfilter/vf_colormap.c +582 −0
Changelog+1−0
@@ -11,6 +11,7 @@ version 5.1: · 10 unmodified lines
11- avsynctest source filter11- avsynctest source filter
12- feedback video filter12- feedback video filter
13- pixelize video filter13- pixelize video filter
14- colormap video filter
14 15
15 16
16version 5.0:17version 5.0:
doc/filters.texi+33−0
@@ -8944,6 +8944,39 @@ colorlevels=romin=0.5:gomin=0.5:bomin=0.5 · 8943 unmodified lines
8944 8944
8945This filter supports the all above options as @ref{commands}.8945This filter supports the all above options as @ref{commands}.
8946 8946
8947@section colormap
8948Apply custom color maps to video stream.
8949
8950This filter needs three input video streams.
8951First stream is video stream that is going to be filtered out.
8952Second and third video stream specify color patches for source
8953color to target color mapping.
8954
8955The filter accepts the following options:
8956
8957@table @option
8958@item patch_size
8959Set the source and target video stream patch size in pixels.
8960
8961@item nb_patches
8962Set the max number of used patches from source and target video stream.
8963
8964@item type
8965Set the adjustments used for target colors. Can be @code{relative} or @code{absolute}.
8966Defaults is @code{absolute}.
8967
8968@item kernel
8969Set the kernel used to measure color differences between mapped colors.
8970
8971The accepted values are:
8972@table @samp
8973@item euclidean
8974@item weuclidean
8975@end table
8976
8977Default is @code{euclidean}.
8978@end table
8979
8947@section colormatrix8980@section colormatrix
8948 8981
8949Convert color matrix.8982Convert color matrix.
libavfilter/Makefile+1−0
@@ -218,6 +218,7 @@ OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \ · 217 unmodified lines
218 opencl/colorkey.o218 opencl/colorkey.o
219OBJS-$(CONFIG_COLORHOLD_FILTER) += vf_colorkey.o219OBJS-$(CONFIG_COLORHOLD_FILTER) += vf_colorkey.o
220OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o220OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o
221OBJS-$(CONFIG_COLORMAP_FILTER) += vf_colormap.o
221OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o222OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o
222OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspace.o colorspacedsp.o223OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspace.o colorspacedsp.o
223OBJS-$(CONFIG_COLORTEMPERATURE_FILTER) += vf_colortemperature.o224OBJS-$(CONFIG_COLORTEMPERATURE_FILTER) += vf_colortemperature.o
libavfilter/allfilters.c+1−0
@@ -204,6 +204,7 @@ extern const AVFilter ff_vf_colorkey; · 203 unmodified lines
204extern const AVFilter ff_vf_colorkey_opencl;204extern const AVFilter ff_vf_colorkey_opencl;
205extern const AVFilter ff_vf_colorhold;205extern const AVFilter ff_vf_colorhold;
206extern const AVFilter ff_vf_colorlevels;206extern const AVFilter ff_vf_colorlevels;
207extern const AVFilter ff_vf_colormap;
207extern const AVFilter ff_vf_colormatrix;208extern const AVFilter ff_vf_colormatrix;
208extern const AVFilter ff_vf_colorspace;209extern const AVFilter ff_vf_colorspace;
209extern const AVFilter ff_vf_colortemperature;210extern const AVFilter ff_vf_colortemperature;
libavfilter/version.h+1−1
@@ -31,7 +31,7 @@ · 30 unmodified lines
31 31
32#include "version_major.h"32#include "version_major.h"
33 33
34#define LIBAVFILTER_VERSION_MINOR 3334#define LIBAVFILTER_VERSION_MINOR 34
35#define LIBAVFILTER_VERSION_MICRO 10035#define LIBAVFILTER_VERSION_MICRO 100
36 36
37 37
libavfilter/vf_colormap.c+582−0
@@ -0,0 +1,582 @@
1/*
2 * Copyright (c) 2022 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * Compute a look-up table from map of colors.
24 */
25
26#include "config_components.h"
27
28#include "libavutil/attributes.h"
29#include "libavutil/avstring.h"
30#include "libavutil/common.h"
31#include "libavutil/opt.h"
32#include "libavutil/pixdesc.h"
33#include "avfilter.h"
34#include "formats.h"
35#include "internal.h"
36#include "framesync.h"
37#include "video.h"
38
39#define MAX_SIZE 64
40
41enum KernelType {
42 EUCLIDEAN,
43 WEUCLIDEAN,
44 NB_KERNELS,
45};
46
47typedef struct ColorMapContext {
48 const AVClass *class;
49 int w, h;
50 int size;
51 int nb_maps;
52 int changed[2];
53
54 float source[MAX_SIZE][4];
55 float ttarget[MAX_SIZE][4];
56 float target[MAX_SIZE][4];
57 float icoeff[4][4];
58 float coeff[MAX_SIZE][4];
59
60 int target_type;
61 int kernel_type;
62 float (*kernel)(const float *x, const float *y);
63
64 FFFrameSync fs;
65} ColorMapContext;
66
67#define OFFSET(x) offsetof(ColorMapContext, x)
68#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
69
70static const AVOption colormap_options[] = {
71 { "patch_size", "set patch size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "64x64"}, 0, 0, FLAGS },
72 { "nb_patches", "set number of patches", OFFSET(size), AV_OPT_TYPE_INT, {.i64 = 8}, 1, MAX_SIZE, FLAGS },
73 { "type", "set the target type used", OFFSET(target_type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "type" },
74 { "relative", "the target colors are relative", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 1, FLAGS, "type" },
75 { "absolute", "the target colors are absolute", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 1, FLAGS, "type" },
76 { "kernel", "set the kernel used for measuring color difference", OFFSET(kernel_type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_KERNELS-1, FLAGS, "kernel" },
77 { "euclidean", "square root of sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64=EUCLIDEAN}, 0, 0, FLAGS, "kernel" },
78 { "weuclidean", "weighted square root of sum of squared differences",0, AV_OPT_TYPE_CONST, {.i64=WEUCLIDEAN}, 0, 0, FLAGS, "kernel" },
79 { NULL }
80};
81
82static int gauss_make_triangular(double *A, int *p, int n)
83{
84 p[n - 1] = n - 1;
85 for (int k = 0; k < n; k++) {
86 double t1;
87 int m = k;
88
89 for (int i = k + 1; i < n; i++)
90 if (fabs(A[k + n * i]) > fabs(A[k + n * m]))
91 m = i;
92 p[k] = m;
93 t1 = A[k + n * m];
94 A[k + n * m] = A[k + n * k];
95 A[k + n * k] = t1;
96 if (t1 != 0) {
97 for (int i = k + 1; i < n; i++)
98 A[k + n * i] /= -t1;
99 if (k != m)
100 for (int i = k + 1; i < n; i++) {
101 double t2 = A[i + n * m];
102 A[i + n * m] = A[i + n * k];
103 A[i + n * k] = t2;
104 }
105 for (int j = k + 1; j < n; j++)
106 for (int i = k + 1; i < n; i++)
107 A[i + n * j] += A[k + j * n] * A[i + k * n];
108 } else {
109 return 0;
110 }
111 }
112
113 return 1;
114}
115
116static void gauss_solve_triangular(const double *A, const int *p, double *b, int n)
117{
118 for(int k = 0; k < n - 1; k++) {
119 int m = p[k];
120 double t = b[m];
121 b[m] = b[k];
122 b[k] = t;
123 for (int i = k + 1; i < n; i++)
124 b[i] += A[k + n * i] * t;
125 }
126
127 for(int k = n - 1; k > 0; k--) {
128 b[k] /= A[k + n * k];
129 double t = b[k];
130 for (int i = 0; i < k; i++)
131 b[i] -= A[k + n * i] * t;
132 }
133
134 b[0] /= A[0 + 0 * n];
135}
136
137static int gauss_solve(double *A, double *b, int n)
138{
139 int *p = av_calloc(n, sizeof(*p));
140
141 if (!p)
142 return 1;
143
144 if (!gauss_make_triangular(A, p, n)) {
145 av_freep(&p);
146 return 1;
147 }
148
149 gauss_solve_triangular(A, p, b, n);
150
151 av_freep(&p);
152
153 return 0;
154}
155
156#define P2(x) ((x)*(x))
157
158static float euclidean_kernel(const float *x, const float *y)
159{
160 const float d2 = P2(x[0]-y[0]) +
161 P2(x[1]-y[1]) +
162 P2(x[2]-y[2]);
163 return sqrtf(d2);
164}
165
166static float weuclidean_kernel(const float *x, const float *y)
167{
168 const float rm = (x[0] + y[0]) * 0.5f;
169 const float d2 = P2(x[0]-y[0]) * (2.f + rm) +
170 P2(x[1]-y[1]) * 4.f +
171 P2(x[2]-y[2]) * (3.f - rm);
172 return sqrtf(d2);
173}
174
175static void build_map(AVFilterContext *ctx)
176{
177 ColorMapContext *s = ctx->priv;
178
179 for (int j = 0; j < s->nb_maps; j++) {
180 s->target[j][0] = s->target_type == 0 ? s->source[j][0] + s->ttarget[j][0] : s->ttarget[j][0];
181 s->target[j][1] = s->target_type == 0 ? s->source[j][1] + s->ttarget[j][1] : s->ttarget[j][1];
182 s->target[j][2] = s->target_type == 0 ? s->source[j][2] + s->ttarget[j][2] : s->ttarget[j][2];
183 }
184
185 for (int c = 0; c < 3; c++) {
186 for (int j = 0; j < s->nb_maps; j++)
187 s->coeff[j][c] = 0.f;
188
189 for (int j = 0; j < 4; j++) {
190 s->icoeff[j][c] = 0;
191 s->icoeff[j][c] = 0;
192 s->icoeff[j][c] = 0;
193 }
194
195 s->icoeff[c+1][c] = 1.f;
196
197 switch (s->nb_maps) {
198 case 1:
199 {
200 float div = fabsf(s->source[0][c]) < 1e-6f ? 1e-6f : s->source[0][c];
201 s->icoeff[c][1+c] = s->target[0][c] / div;
202 }
203 break;
204 case 2:
205 {
206 double A[2 * 2] = { 1, s->source[0][c],
207 1, s->source[1][c] };
208 double b[2] = { s->target[0][c], s->target[1][c] };
209
210 if (gauss_solve(A, b, 2))
211 continue;
212
213 s->icoeff[0 ][c] = b[0];
214 s->icoeff[1+c][c] = b[1];
215 }
216 break;
217 case 3:
218 {
219 const uint8_t idx[3][3] = {{ 0, 1, 2 },
220 { 1, 0, 2 },
221 { 2, 0, 1 }};
222 const uint8_t didx[3][4] = {{ 0, 1, 2, 2 },
223 { 0, 2, 1, 2 },
224 { 0, 2, 2, 1 }};
225 const int C0 = idx[c][0];
226 const int C1 = idx[c][1];
227 const int C2 = idx[c][2];
228 double A[3 * 3] = { 1, s->source[0][C0], s->source[0][C1] + s->source[0][C2],
229 1, s->source[1][C0], s->source[1][C1] + s->source[1][C2],
230 1, s->source[2][C0], s->source[2][C1] + s->source[2][C2] };
231 double b[3] = { s->target[0][c], s->target[1][c], s->target[2][c] };
232
233 if (gauss_solve(A, b, 3))
234 continue;
235
236 s->icoeff[0][c] = b[didx[c][0]];
237 s->icoeff[1][c] = b[didx[c][1]];
238 s->icoeff[2][c] = b[didx[c][2]];
239 s->icoeff[3][c] = b[didx[c][3]];
240 }
241 break;
242 case 4:
243 {
244 double A[4 * 4] = { 1, s->source[0][0], s->source[0][1], s->source[0][2],
245 1, s->source[1][0], s->source[1][1], s->source[1][2],
246 1, s->source[2][0], s->source[2][1], s->source[2][2],
247 1, s->source[3][0], s->source[3][1], s->source[3][2] };
248 double b[4] = { s->target[0][c], s->target[1][c], s->target[2][c], s->target[3][c] };
249 int pivot[4];
250
251 if (!gauss_make_triangular(A, pivot, 4))
252 continue;
253 gauss_solve_triangular(A, pivot, b, 4);
254
255 s->icoeff[0][c] = b[0];
256 s->icoeff[1][c] = b[1];
257 s->icoeff[2][c] = b[2];
258 s->icoeff[3][c] = b[3];
259 }
260 break;
261 default:
262 {
263 const int N = s->nb_maps;
264 const int N4 = N + 4;
265 double *A = av_calloc(sizeof(*A), N4 * N4);
266 double *b = av_calloc(sizeof(*b), N4);
267 int *pivot = NULL;
268
269 if (!A || !b)
270 goto error;
271
272 for (int j = 0; j < N; j++)
273 for (int i = j; i < N; i++)
274 A[j*N4+i] = A[i*N4+j] = s->kernel(s->source[i], s->source[j]);
275
276 for (int i = 0; i < N; i++)
277 A[i*N4+N+0] = A[(N+0)*N4+i] = 1;
278 for (int i = 0; i < N; i++)
279 A[i*N4+N+1] = A[(N+1)*N4+i] = s->source[i][0];
280 for (int i = 0; i < N; i++)
281 A[i*N4+N+2] = A[(N+2)*N4+i] = s->source[i][1];
282 for (int i = 0; i < N; i++)
283 A[i*N4+N+3] = A[(N+3)*N4+i] = s->source[i][2];
284
285 for (int j = N; j < N4; j++)
286 for (int i = N;i < N4; i++)
287 A[j * N4 + i] = 0.;
288
289 pivot = av_calloc(N4, sizeof(*pivot));
290 if (!pivot)
291 goto error;
292
293 if (gauss_make_triangular(A, pivot, N4)) {
294 for (int i = 0; i < N; i++)
295 b[i] = s->target[i][c];
296 for (int i = N; i < N + 4; i++)
297 b[i] = 0;
298
299 gauss_solve_triangular(A, pivot, b, N4);
300
301 for (int i = 0; i < N; i++)
302 s->coeff[i][c] = b[i];
303
304 for (int i = 0; i < 4; i++)
305 s->icoeff[i][c] = b[N + i];
306 }
307error:
308 av_free(pivot);
309 av_free(b);
310 av_free(A);
311 }
312 }
313 }
314}
315
316typedef struct ThreadData {
317 AVFrame *in, *out;
318} ThreadData;
319
320static int colormap_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
321{
322 ColorMapContext *s = ctx->priv;
323 ThreadData *td = arg;
324 AVFrame *in = td->in;
325 AVFrame *out = td->out;
326 const int maps = s->nb_maps;
327 const int width = out->width;
328 const int height = out->height;
329 const int slice_start = (height * jobnr) / nb_jobs;
330 const int slice_end = (height * (jobnr + 1)) / nb_jobs;
331 const int sr_linesize = in->linesize[2] / 4;
332 const int dr_linesize = out->linesize[2] / 4;
333 const int sg_linesize = in->linesize[0] / 4;
334 const int dg_linesize = out->linesize[0] / 4;
335 const int sb_linesize = in->linesize[1] / 4;
336 const int db_linesize = out->linesize[1] / 4;
337 const float *sr = (float *)in->data[2] + slice_start * sr_linesize;
338 const float *sg = (float *)in->data[0] + slice_start * sg_linesize;
339 const float *sb = (float *)in->data[1] + slice_start * sb_linesize;
340 float *r = (float *)out->data[2] + slice_start * dr_linesize;
341 float *g = (float *)out->data[0] + slice_start * dg_linesize;
342 float *b = (float *)out->data[1] + slice_start * db_linesize;
343 float (*kernel)(const float *x, const float *y) = s->kernel;
344 const float *icoeff[4] = { s->icoeff[0], s->icoeff[1], s->icoeff[2], s->icoeff[3] };
345
346 for (int y = slice_start; y < slice_end; y++) {
347 for (int x = 0; x < width; x++) {
348 const float input[3] = { sr[x], sg[x], sb[x] };
349 float srv, sgv, sbv;
350 float rv, gv, bv;
351
352 srv = sr[x];
353 sgv = sg[x];
354 sbv = sb[x];
355
356 rv = icoeff[0][0];
357 gv = icoeff[0][1];
358 bv = icoeff[0][2];
359
360 rv += icoeff[1][0] * srv + icoeff[2][0] * sgv + icoeff[3][0] * sbv;
361 gv += icoeff[1][1] * srv + icoeff[2][1] * sgv + icoeff[3][1] * sbv;
362 bv += icoeff[1][2] * srv + icoeff[2][2] * sgv + icoeff[3][2] * sbv;
363
364 for (int z = 0; z < maps && maps > 4; z++) {
365 const float *coeff = s->coeff[z];
366 const float cr = coeff[0];
367 const float cg = coeff[1];
368 const float cb = coeff[2];
369 const float f = kernel(input, s->source[z]);
370
371 rv += f * cr;
372 gv += f * cg;
373 bv += f * cb;
374 }
375
376 r[x] = rv;
377 g[x] = gv;
378 b[x] = bv;
379 }
380
381 sg += sg_linesize;
382 g += dg_linesize;
383 sb += sb_linesize;
384 b += db_linesize;
385 sr += sr_linesize;
386 r += dr_linesize;
387 }
388
389 return 0;
390}
391
392static int import_map(AVFilterLink *inlink, AVFrame *in)
393{
394 AVFilterContext *ctx = inlink->dst;
395 ColorMapContext *s = ctx->priv;
396 const int is_target = FF_INLINK_IDX(inlink) > 1;
397 const int pw = s->w;
398 const int pw2 = s->w / 2;
399 const int ph = s->h;
400 const int ph2 = s->h / 2;
401 int changed = 0;
402 int idx;
403
404 for (int plane = 0; plane < 3; plane++) {
405 const int c = plane == 0 ? 1 : plane == 1 ? 2 : 0;
406
407 idx = 0;
408 for (int y = ph2; y < in->height && idx < MAX_SIZE; y += ph) {
409 const float *src = (const float *)(in->data[plane] + y * in->linesize[plane]);
410
411 for (int x = pw2; x < in->width && idx < MAX_SIZE; x += pw) {
412 float value = src[x];
413
414 if (is_target) {
415 if (s->ttarget[idx][c] != value)
416 changed = 1;
417 s->ttarget[idx][c] = value;
418 } else {
419 if (s->source[idx][c] != value)
420 changed = 1;
421 s->source[idx][c] = value;
422 }
423
424 idx++;
425 }
426 }
427 }
428
429 if (changed)
430 s->changed[is_target] = 1;
431 if (!is_target)
432 s->nb_maps = FFMIN(idx, s->size);
433
434 return 0;
435}
436
437static int process_frame(FFFrameSync *fs)
438{
439 AVFilterContext *ctx = fs->parent;
440 ColorMapContext *s = fs->opaque;
441 AVFilterLink *outlink = ctx->outputs[0];
442 AVFrame *in, *out, *source, *target;
443 ThreadData td;
444 int ret;
445
446 switch (s->kernel_type) {
447 case EUCLIDEAN:
448 s->kernel = euclidean_kernel;
449 break;
450 case WEUCLIDEAN:
451 s->kernel = weuclidean_kernel;
452 break;
453 default:
454 return AVERROR_BUG;
455 }
456
457 if ((ret = ff_framesync_get_frame(&s->fs, 0, &in, 1)) < 0 ||
458 (ret = ff_framesync_get_frame(&s->fs, 1, &source, 0)) < 0 ||
459 (ret = ff_framesync_get_frame(&s->fs, 2, &target, 0)) < 0)
460 return ret;
461
462 import_map(ctx->inputs[1], source);
463 import_map(ctx->inputs[2], target);
464
465 if (s->changed[0] || s->changed[1]) {
466 build_map(ctx);
467 s->changed[0] = s->changed[1] = 0;
468 }
469
470 if (!ctx->is_disabled) {
471 if (av_frame_is_writable(in)) {
472 out = in;
473 } else {
474 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
475 if (!out) {
476 av_frame_free(&in);
477 return AVERROR(ENOMEM);
478 }
479 av_frame_copy_props(out, in);
480 }
481
482 td.in = in;
483 td.out = out;
484 ff_filter_execute(ctx, colormap_slice, &td, NULL,
485 FFMIN(in->height, ff_filter_get_nb_threads(ctx)));
486
487 if (out != in)
488 av_frame_free(&in);
489 } else {
490 out = in;
491 }
492
493 out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base);
494
495 return ff_filter_frame(outlink, out);
496}
497
498static int config_output(AVFilterLink *outlink)
499{
500 AVFilterContext *ctx = outlink->src;
501 ColorMapContext *s = ctx->priv;
502 AVFilterLink *inlink = ctx->inputs[0];
503 AVFilterLink *source = ctx->inputs[1];
504 AVFilterLink *target = ctx->inputs[2];
505 FFFrameSyncIn *in;
506 int ret;
507
508 outlink->time_base = inlink->time_base;
509 outlink->frame_rate = inlink->frame_rate;
510 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
511 outlink->w = inlink->w;
512 outlink->h = inlink->h;
513
514 if ((ret = ff_framesync_init(&s->fs, ctx, 3)) < 0)
515 return ret;
516
517 in = s->fs.in;
518 in[0].time_base = inlink->time_base;
519 in[1].time_base = source->time_base;
520 in[2].time_base = target->time_base;
521 in[0].sync = 1;
522 in[0].before = EXT_STOP;
523 in[0].after = EXT_INFINITY;
524 in[1].sync = 1;
525 in[1].before = EXT_STOP;
526 in[1].after = EXT_INFINITY;
527 in[2].sync = 1;
528 in[2].before = EXT_STOP;
529 in[2].after = EXT_INFINITY;
530 s->fs.opaque = s;
531 s->fs.on_event = process_frame;
532
533 ret = ff_framesync_configure(&s->fs);
534 outlink->time_base = s->fs.time_base;
535
536 return ret;
537}
538
539static int activate(AVFilterContext *ctx)
540{
541 ColorMapContext *s = ctx->priv;
542 return ff_framesync_activate(&s->fs);
543}
544
545static const AVFilterPad inputs[] = {
546 {
547 .name = "default",
548 .type = AVMEDIA_TYPE_VIDEO,
549 },
550 {
551 .name = "source",
552 .type = AVMEDIA_TYPE_VIDEO,
553 },
554 {
555 .name = "target",
556 .type = AVMEDIA_TYPE_VIDEO,
557 },
558};
559
560static const AVFilterPad outputs[] = {
561 {
562 .name = "default",
563 .type = AVMEDIA_TYPE_VIDEO,
564 .config_props = config_output,
565 },
566};
567
568AVFILTER_DEFINE_CLASS(colormap);
569
570const AVFilter ff_vf_colormap = {
571 .name = "colormap",
572 .description = NULL_IF_CONFIG_SMALL("Apply custom Color Maps to video stream."),
573 .priv_class = &colormap_class,
574 .priv_size = sizeof(ColorMapContext),
575 .activate = activate,
576 FILTER_INPUTS(inputs),
577 FILTER_OUTPUTS(outputs),
578 FILTER_PIXFMTS(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32),
579 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
580 AVFILTER_FLAG_SLICE_THREADS,
581 .process_command = ff_filter_process_command,
582};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t