FFmpeg
Loading...
Searching...
No Matches
vf_gainmap.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19/**
20 * @file
21 * Filter to compute an HDR gain map from a base and alternate rendition.
22 */
23
24#include <float.h>
25#include <math.h>
26
27#include "libavutil/csp.h"
28#include "libavutil/gain_map.h"
29#include "libavutil/internal.h"
31#include "libavutil/mem.h"
32#include "libavutil/opt.h"
33#include "libavutil/pixdesc.h"
34
35#include "avfilter.h"
36#include "colorspace.h"
37#include "filters.h"
38#include "formats.h"
39#include "framesync.h"
40#include "video.h"
41
42#define SDR_DIFFUSE_WHITE 203.0
43
45 GAINMAP_CSP_BASE, ///< apply the map in the base rendition's space
46 GAINMAP_CSP_ALT, ///< apply it in the alternate rendition's space
48};
49
51 GAINMAP_RGB, ///< one channel per component
52 GAINMAP_LUMA, ///< single channel, from the luminance
53 GAINMAP_MAXRGB, ///< single channel, from max(R,G,B)
55};
56
64
65typedef struct GainMapEOTF {
68 double Lw;
69
70#define GAINMAP_LUT_SIZE 1025
71 float lut[GAINMAP_LUT_SIZE + 1]; /* extra padding entry */
73
74typedef struct GainMapContext {
75 const AVClass *class;
77
78 /* Filter options */
79 int mode;
88
91 int nb_threads; /* for slice threading */
92 int convert; /* colorspace conversion needed */
93 int sign; /* sign(alt_peak - base_peak) */
94
95 /* Colorspace parameters */
98 float rgb2y[3];
99 float rgb2rgb[3][3];
100
101 /* Quantization parameters, either static or recomputed dynamically */
102 float quant_scale[3];
103 float quant_offset[3];
104 float quant_gamma[3];
105
106 /* Measured frame statistics */
107 float (*slice_min)[3]; /* for MEASURE_MIN */
108 float (*slice_max)[3]; /* for MEASURE_MAX */
109 double (*slice_sum)[3]; /* for MEASURE_GAMMA */
111
112 /* Generated gain map parameters (recomputed per frame) */
116
117typedef struct ThreadData {
118 AVFrame *out;
119 const AVFrame *base, *alt;
120} ThreadData;
121
122#define OFFSET(x) offsetof(GainMapContext, x)
123#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
124
125static const AVOption gainmap_options[] = {
126 { "mode", "quantity the gain is computed over", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = GAINMAP_RGB }, 0, GAINMAP_MODE_NB - 1, FLAGS, .unit = "mode" },
127 { "rgb", "one gain channel per component", 0, AV_OPT_TYPE_CONST, { .i64 = GAINMAP_RGB }, 0, 0, FLAGS, .unit = "mode" },
128 { "luma", "single gain channel, from luminance", 0, AV_OPT_TYPE_CONST, { .i64 = GAINMAP_LUMA }, 0, 0, FLAGS, .unit = "mode" },
129 { "maxrgb", "single gain channel, from max(R,G,B)", 0, AV_OPT_TYPE_CONST, { .i64 = GAINMAP_MAXRGB }, 0, 0, FLAGS, .unit = "mode" },
130 { "colorspace", "rendition whose colour space the map is applied in", OFFSET(colorspace), AV_OPT_TYPE_INT, { .i64 = GAINMAP_CSP_BASE }, 0, GAINMAP_CSP_NB - 1, FLAGS, .unit = "colorspace" },
131 { "base", "the base rendition's colour space", 0, AV_OPT_TYPE_CONST, { .i64 = GAINMAP_CSP_BASE }, 0, 0, FLAGS, .unit = "colorspace" },
132 { "alternate", "the alternate rendition's colour space", 0, AV_OPT_TYPE_CONST, { .i64 = GAINMAP_CSP_ALT }, 0, 0, FLAGS, .unit = "colorspace" },
133 { "min", "override lower bound on the encoded gain, in log2 space", OFFSET(gain_min), AV_OPT_TYPE_RATIONAL, { .dbl = NAN }, -32.0, 32.0, FLAGS },
134 { "max", "override upper bound on the encoded gain, in log2 space", OFFSET(gain_max), AV_OPT_TYPE_RATIONAL, { .dbl = NAN }, -32.0, 32.0, FLAGS },
135 { "gamma", "override encoding gamma of the stored map (default: measured)", OFFSET(gamma), AV_OPT_TYPE_RATIONAL, { .dbl = NAN }, 0.0001, 100.0, FLAGS },
136 { "base_offset", "constant added to the base rendition", OFFSET(base_offset), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 / 64.0 }, 1e-6, 1.0, FLAGS },
137 { "alt_offset", "constant added to the alternate rendition", OFFSET(alt_offset), AV_OPT_TYPE_RATIONAL, { .dbl = 1.0 / 64.0 }, 1e-6, 1.0, FLAGS },
138 { "base_nits", "override input luminance of the base rendition", OFFSET(base_nits), AV_OPT_TYPE_RATIONAL, { .dbl = NAN }, 1.0, 10000.0, FLAGS },
139 { "alt_nits", "override input luminance of the alternate rendition", OFFSET(alt_nits), AV_OPT_TYPE_RATIONAL, { .dbl = NAN }, 1.0, 10000.0, FLAGS },
140 { NULL }
141};
142
144
145/* Quantize to a fixed point representation with the correct rounding mode */
146static AVRational quantq(double x, enum AVRounding rnd)
147{
148 const int scale = 1 << 22;
149
150 switch (rnd) {
151 case AV_ROUND_DOWN: x = floor(x * scale); break;
152 case AV_ROUND_UP: x = ceil(x * scale); break;
153 case AV_ROUND_NEAR_INF: x = round(x * scale); break;
154 default: av_unreachable("not used / implemented");
155 }
156
157 AVRational q;
158 av_reduce(&q.num, &q.den, x, scale, INT_MAX);
159 return q;
160}
161
163{
164 GainMapContext *s = ctx->priv;
165 if (av_cmp_q(max, min) <= 0) {
166 /* Nothing to quantize; flat gain map */
167 s->quant_scale[ch] = s->quant_offset[ch] = 0.0f;
168 max = min; /* sanity */
169 } else {
170 const float minf = av_q2d(min), maxf = av_q2d(max);
171 s->quant_scale[ch] = 1.0f / (maxf - minf);
172 s->quant_offset[ch] = -minf * s->quant_scale[ch];
173 }
174
175 s->params->channels[ch].gain_map_min = min;
176 s->params->channels[ch].gain_map_max = max;
177 av_log(ctx, AV_LOG_TRACE, "channel %d: measured min=%g max=%g\n",
178 ch, av_q2d(min), av_q2d(max));
179}
180
181static void setup_gamma(AVFilterContext *ctx, int ch, AVRational gamma)
182{
183 GainMapContext *s = ctx->priv;
184 s->quant_gamma[ch] = av_q2d(gamma);
185 s->params->channels[ch].gamma = gamma;
186 av_log(ctx, AV_LOG_TRACE, "channel %d: measured gamma=%g\n",
187 ch, s->quant_gamma[ch]);
188}
189
191{
192 GainMapContext *s = ctx->priv;
193
194 if (av_cmp_q(s->gain_min, s->gain_max) >= 0) {
195 av_log(ctx, AV_LOG_ERROR, "min (%g) must be below max (%g)\n",
196 av_q2d(s->gain_min), av_q2d(s->gain_max));
197 return AVERROR(EINVAL);
198 }
199
200 s->nb_channels = s->mode == GAINMAP_RGB ? 3 : 1;
201 if (!s->gain_min.den)
202 s->measure |= MEASURE_MIN;
203 if (!s->gain_max.den)
204 s->measure |= MEASURE_MAX;
205 if (!s->gamma.den)
206 s->measure |= MEASURE_GAMMA;
207 if (s->measure) {
208 av_log(ctx, AV_LOG_VERBOSE, "Using two passes to measure gain map "
209 "parameters from the input frame.\n");
210 }
211
212 s->params = av_gain_map_params_alloc(&s->params_size);
213 if (!s->params)
214 return AVERROR(ENOMEM);
215
216 /* payload metadata recomputed per frame */
217 s->params->version = 0;
218 s->params->nb_channels = s->nb_channels;
219 s->params->use_base_color_space = s->colorspace == GAINMAP_CSP_BASE;
220
221 for (int c = 0; c < s->nb_channels; c++) {
222 struct AVGainMapChannel *ch = &s->params->channels[c];
223 ch->base_offset = s->base_offset;
224 ch->alternate_offset = s->alt_offset;
225 if (!(s->measure & MEASURE_RANGE))
226 setup_range(ctx, c, s->gain_min, s->gain_max);
227 if (!(s->measure & MEASURE_GAMMA))
228 setup_gamma(ctx, c, s->gamma);
229 }
230
231 return 0;
232}
233
235 AVFilterFormatsConfig **cfg_in,
236 AVFilterFormatsConfig **cfg_out)
237{
238 const GainMapContext *s = ctx->priv;
239 enum AVPixelFormat in_fmt, out_fmt;
240 int ret;
241
242 in_fmt = AV_PIX_FMT_GBRPF32;
243 out_fmt = s->nb_channels == 1 ? AV_PIX_FMT_GRAYF32 : AV_PIX_FMT_GBRPF32;
244
246 if (ret < 0)
247 return ret;
248
249 return ff_set_common_formats2(ctx, cfg_in, cfg_out,
251}
252
253static double frame_luminance(const AVFrame *frame)
254{
255 const AVFrameSideData *sd;
257 if (sd) {
259 mdm = (const AVMasteringDisplayMetadata *) sd->data;
260 if (mdm->has_luminance && mdm->max_luminance.num > 0)
261 return av_q2d(mdm->max_luminance);
262 }
263
264 switch (frame->color_trc) {
265 case AVCOL_TRC_SMPTE2084: return 10000.0;
266 case AVCOL_TRC_ARIB_STD_B67: return 1000.0;
267 default: return SDR_DIFFUSE_WHITE;
268 }
269}
270
272 av_csp_eotf_function eotf, double Lw)
273{
274 if (trc == tf->trc && Lw == tf->Lw)
275 return; /* no change */
276 tf->trc = trc;
277 tf->Lw = Lw;
278
279 switch (trc) {
280 /* EOTFs that are safe to collapse into a 1D LUT */
281 case AVCOL_TRC_BT709:
286 case AVCOL_TRC_LINEAR:
292 case AVCOL_TRC_SMPTE2084: {
293 for (int i = 0; i < GAINMAP_LUT_SIZE; i++) {
294 double x[3] = { i / (GAINMAP_LUT_SIZE - 1.0) };
295 eotf(Lw, 0.0, x);
296 tf->lut[i] = x[0] / SDR_DIFFUSE_WHITE; /* normalize */
297 }
298
300 tf->eotf = NULL;
301 break;
302 }
303 /* EOTFs that use the av_csp_eotf_function fallback */
304 case AVCOL_TRC_ARIB_STD_B67: /* nontrivial OOTF */
305 case AVCOL_TRC_SMPTE428: /* different normalization per channel */
306 default:
307 tf->eotf = eotf;
308 break;
309 }
310}
311
312static const char *unknown_if_null(const char *s)
313{
314 return s ? s : "unknown";
315}
316
317/* Run per frame, since trc/primaries are not (yet) link-level properties */
319{
320 GainMapContext *const s = ctx->priv;
321 av_csp_eotf_function base_eotf = av_csp_itu_eotf(base->color_trc);
322 av_csp_eotf_function alt_eotf = av_csp_itu_eotf(alt->color_trc);
323 if (!base_eotf || !alt_eotf) {
324 av_log(ctx, AV_LOG_ERROR, "Unknown transfer: base=%s, alternate=%s\n",
327 return AVERROR(EINVAL);
328 }
329
330 const AVColorPrimariesDesc *base_desc, *alt_desc;
331 base_desc = av_csp_primaries_desc_from_id(base->color_primaries);
332 alt_desc = av_csp_primaries_desc_from_id(alt->color_primaries);
333 if (!base_desc || !alt_desc) {
334 av_log(ctx, AV_LOG_ERROR, "Unknown primaries: base=%s, alternate=%s\n",
336 unknown_if_null(av_color_primaries_name(alt->color_primaries)));
337 return AVERROR(EINVAL);
338 }
339
340 double base_lw = s->base_nits.den ? av_q2d(s->base_nits) : frame_luminance(base);
341 double alt_lw = s->alt_nits.den ? av_q2d(s->alt_nits) : frame_luminance(alt);
342 double base_headroom = fmax(log2(base_lw / SDR_DIFFUSE_WHITE), 0.0);
343 double alt_headroom = fmax(log2(alt_lw / SDR_DIFFUSE_WHITE), 0.0);
344 s->params->base_hdr_headroom = quantq(base_headroom, AV_ROUND_NEAR_INF);
345 s->params->alternate_hdr_headroom = quantq(alt_headroom, AV_ROUND_NEAR_INF);
346 s->sign = FFDIFFSIGN(alt_headroom, base_headroom);
347 if (!s->sign) {
348 /* No-op, set up empty gain map */
349 for (int i = 0; i < s->nb_channels; i++) {
350 setup_range(ctx, i, (AVRational) { 0, 1 }, (AVRational) { 0, 1 });
351 setup_gamma(ctx, i, (AVRational) { 1, 1 });
352 }
353
355 "Base and alternate renditions have the same peak "
356 "luminance (%g nits), gain map will be empty\n", base_lw);
357 return 0;
358 } else {
359 av_log(ctx, AV_LOG_DEBUG, "Base peak: %g nits, alternate peak: %g nits\n",
360 base_lw, alt_lw);
361 }
362
363 update_eotf(&s->base_eotf, base->color_trc, base_eotf, base_lw);
364 update_eotf(&s->alt_eotf, alt->color_trc, alt_eotf, alt_lw);
365
366 /* Assume conversion from alt to base */
367 if (s->colorspace == GAINMAP_CSP_ALT)
368 FFSWAP(const AVColorPrimariesDesc *, base_desc, alt_desc);
369
370 double rgb2xyz[3][3];
371 ff_fill_rgb2xyz_table(&base_desc->prim, &base_desc->wp, rgb2xyz);
372 for (int i = 0; i < 3; i++)
373 s->rgb2y[i] = rgb2xyz[1][i] / av_q2d(base_desc->wp.y);
374
375 s->convert = base->color_primaries != alt->color_primaries;
376 if (s->convert) {
377 /* Note: Ignores whitepoint differences (chromatic adaptation) */
378 double xyz2rgb[3][3], rgb2rgb[3][3];
379 ff_fill_rgb2xyz_table(&base_desc->prim, &base_desc->wp, rgb2xyz);
381 ff_fill_rgb2xyz_table(&alt_desc->prim, &alt_desc->wp, rgb2xyz);
382 ff_matrix_mul_3x3(rgb2rgb, rgb2xyz, xyz2rgb);
383 for (int i = 0; i < 3; i++)
384 for (int j = 0; j < 3; j++)
385 s->rgb2rgb[i][j] = (float) rgb2rgb[i][j];
386 } else {
387 memset(s->rgb2rgb, 0, sizeof(s->rgb2rgb));
388 for (int i = 0; i < 3; i++)
389 s->rgb2rgb[i][i] = 1.0f;
390 }
391
392 return 0;
393}
394
395static av_always_inline float quantize(float gain, float scale, float offset, float gamma)
396{
397 const float norm = av_clipf(scale * gain + offset, 0.0f, 1.0f);
398 return gamma == 1.0f ? norm : powf(norm, gamma);
399}
400
401static av_always_inline void
402get_pixel(const GainMapContext *s, float dst[3],
403 const float *restrict const src[3], int x, int alt)
404{
405 const GainMapEOTF *const tf = alt ? &s->alt_eotf : &s->base_eotf;
406 float rgb[3];
407
408 /* Linearize to normalized RGB */
409 if (tf->eotf) {
410 double rgbd[3] = { src[0][x], src[1][x], src[2][x] };
411 tf->eotf(tf->Lw, 0.0, rgbd);
412 for (int i = 0; i < 3; i++)
413 rgb[i] = rgbd[i] / SDR_DIFFUSE_WHITE;
414 } else {
415 for (int i = 0; i < 3; i++) {
416 const float fx = av_clipf(src[i][x], 0.0f, 1.0f) * (GAINMAP_LUT_SIZE - 1.0);
417 const int ix = (int) fx;
418 const float lo = tf->lut[ix];
419 const float hi = tf->lut[ix + 1];
420 rgb[i] = lo + (fx - ix) * (hi - lo);
421 }
422 }
423
424 /* Convert to correct colorspace if needed */
425 if (s->convert && (s->colorspace == GAINMAP_CSP_ALT) != alt) {
426 const float r = rgb[0], g = rgb[1], b = rgb[2];
427 for (int i = 0; i < 3; i++) {
428 dst[i] = fmaxf(r * s->rgb2rgb[i][0] +
429 g * s->rgb2rgb[i][1] +
430 b * s->rgb2rgb[i][2], 0.0f);
431 }
432 } else {
433 for (int i = 0; i < 3; i++)
434 dst[i] = fmaxf(rgb[i], 0.0f);
435 }
436}
437
438/* GBRP plane order */
439static const int gbr_order[3] = { 2, 0, 1 };
440
441static av_always_inline int
442slice_internal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, int quant)
443{
444 GainMapContext *s = ctx->priv;
445 const ThreadData *td = arg;
446 const AVFrame *base = td->base, *alt = td->alt, *out = td->out;
447
448 const float *restrict scale = s->quant_scale;
449 const float *restrict offset = s->quant_offset;
450 const float *restrict gamma = s->quant_gamma;
451
452 /* Normalize both to the base colorspace */
453 const float base_off = av_q2d(s->base_offset);
454 const float alt_off = av_q2d(s->alt_offset);
455 const float sign = s->sign;
456
457 const int y_start = ff_slice_pos(out->height, jobnr, nb_jobs);
458 const int y_end = ff_slice_pos(out->height, jobnr + 1, nb_jobs);
459 const int width = out->width;
460 const int mode = s->mode;
461 const int nb_ch = s->nb_channels;
462
463 float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
464 float max[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
465 double sum[3] = { 0.0, 0.0, 0.0 };
466
467 for (int y = y_start; y < y_end; y++) {
468 const float *restrict b_row[3], *restrict a_row[3];
469 for (int i = 0; i < 3; i++) {
470 const int p = gbr_order[i];
471 b_row[i] = (const float *) (base->data[p] + y * base->linesize[p]);
472 a_row[i] = (const float *) ( alt->data[p] + y * alt->linesize[p]);
473 }
474
475 float *restrict out_row[3];
476 for (int i = 0; i < nb_ch; i++) {
477 const int p = nb_ch == 1 ? 0 : gbr_order[i];
478 out_row[i] = (float *) (out->data[p] + y * out->linesize[p]);
479 }
480
481 for (int x = 0; x < width; x++) {
482 float b[3], a[3], gain[3];
483 get_pixel(s, b, b_row, x, 0);
484 get_pixel(s, a, a_row, x, 1);
485
486 #define GAIN(a, b) (sign * log2f(((a) + alt_off) / ((b) + base_off)))
487 switch (mode) {
488 case GAINMAP_MAXRGB: {
489 const float max_a = fmaxf(fmaxf(a[0], a[1]), a[2]);
490 const float max_b = fmaxf(fmaxf(b[0], b[1]), b[2]);
491 gain[0] = GAIN(max_a, max_b);
492 break;
493 }
494 case GAINMAP_LUMA: {
495 const float y_a = s->rgb2y[0] * a[0] + s->rgb2y[1] * a[1] + s->rgb2y[2] * a[2];
496 const float y_b = s->rgb2y[0] * b[0] + s->rgb2y[1] * b[1] + s->rgb2y[2] * b[2];
497 gain[0] = GAIN(y_a, y_b);
498 break;
499 }
500 case GAINMAP_RGB:
501 gain[0] = GAIN(a[0], b[0]);
502 gain[1] = GAIN(a[1], b[1]);
503 gain[2] = GAIN(a[2], b[2]);
504 break;
505 }
506 #undef GAIN
507
508 if (quant) {
509 for (int i = 0; i < nb_ch; i++)
510 out_row[i][x] = quantize(gain[i], scale[i], offset[i], gamma[i]);
511 } else {
512 for (int i = 0; i < nb_ch; i++) {
513 out_row[i][x] = gain[i];
514 min[i] = fminf(min[i], gain[i]);
515 max[i] = fmaxf(max[i], gain[i]);
516 sum[i] += gain[i];
517 }
518 }
519
520 }
521 }
522
523 for (int i = 0; !quant && i < 3; i++) {
524 s->slice_min[jobnr][i] = min[i];
525 s->slice_max[jobnr][i] = max[i];
526 s->slice_sum[jobnr][i] = sum[i];
527 }
528
529 return 0;
530}
531
532static int slice_gain(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
533{
534 return slice_internal(ctx, arg, jobnr, nb_jobs, 0);
535}
536
537static int slice_gain_quant(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
538{
539 return slice_internal(ctx, arg, jobnr, nb_jobs, 1);
540}
541
542static int slice_quant(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
543{
544 const ThreadData *td = arg;
545 const GainMapContext *s = ctx->priv;
546 const AVFrame *out = td->out;
547
548 const float *restrict scale = s->quant_scale;
549 const float *restrict offset = s->quant_offset;
550 const float *restrict gamma = s->quant_gamma;
551
552 const int y_start = ff_slice_pos(out->height, jobnr, nb_jobs);
553 const int y_end = ff_slice_pos(out->height, jobnr + 1, nb_jobs);
554 const int width = out->width;
555 const int nb_ch = s->nb_channels;
556
557 for (int y = y_start; y < y_end; y++) {
558 float *restrict out_row[3];
559 for (int i = 0; i < nb_ch; i++) {
560 const int p = nb_ch == 1 ? 0 : gbr_order[i];
561 out_row[i] = (float *) (out->data[p] + y * out->linesize[p]);
562 }
563
564 for (int x = 0; x < width; x++) {
565 for (int i = 0; i < nb_ch; i++)
566 out_row[i][x] = quantize(out_row[i][x], scale[i], offset[i], gamma[i]);
567 }
568 }
569
570 return 0;
571}
572
573static void choose_quant_params(AVFilterContext *ctx, const AVFrame *out, int nb_jobs)
574{
575 GainMapContext *s = ctx->priv;
576 float frame_min[3] = { FLT_MAX, FLT_MAX, FLT_MAX };
577 float frame_max[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX };
578 double frame_sum[3] = { 0.0, 0.0, 0.0 };
579
580 for (int j = 0; j < nb_jobs; j++) {
581 for (int i = 0; i < s->nb_channels; i++) {
582 frame_min[i] = fminf(frame_min[i], s->slice_min[j][i]);
583 frame_max[i] = fmaxf(frame_max[i], s->slice_max[j][i]);
584 frame_sum[i] += s->slice_sum[j][i];
585 }
586 }
587
588 for (int i = 0; i < s->nb_channels; i++) {
589 AVRational min = s->gain_min, max = s->gain_max;
590 if (s->measure & MEASURE_MIN)
591 min = quantq(frame_min[i], AV_ROUND_DOWN);
592 if (s->measure & MEASURE_MAX)
593 max = quantq(frame_max[i], AV_ROUND_UP);
594 if (s->measure & MEASURE_RANGE)
595 setup_range(ctx, i, min, max);
596
597 if (!(s->measure & MEASURE_GAMMA))
598 continue;
599
600 const int64_t nb_pixels = (int64_t) out->width * out->height;
601 const double mean = frame_sum[i] / nb_pixels;
602 const double mean_quant = s->quant_scale[i] * mean + s->quant_offset[i];
603
604 /**
605 * Choose gamma such that mean_quant ^ gamma = 0.5; clamp to a sane
606 * value range of [1/8, 8] to prevent degenerate encodings. A gamma
607 * of >8 would collapse half the encoding space into a single 8-bit
608 * value, at which point we're losing more then gaining, and a value
609 * of <1/8 limits the amount by which a single high outlier pixel
610 * can determine the overall encoding gamma.
611 *
612 * We also clamp the mean to [0.01, 0.99] to prevent numerical explosion
613 * in the case that the mean is very close to 0 or 1. This is a looser
614 * bound than the final gamma clamp, so the exact values chosen do not
615 * matter as much.
616 */
617 double gamma = log(0.5) / log(av_clipd(mean_quant, 0.01, 0.99));
618 setup_gamma(ctx, i, quantq(av_clipd(gamma, 1/8.0, 8.0), AV_ROUND_NEAR_INF));
619 }
620}
621
623{
624 AVFilterContext *ctx = fs->parent;
625 GainMapContext *s = ctx->priv;
626 AVFilterLink *outlink = ctx->outputs[0];
627 AVFrame *base, *alt, *out;
628
629 int ret;
630 if ((ret = ff_framesync_get_frame(fs, 0, &base, 0)) < 0 ||
631 (ret = ff_framesync_get_frame(fs, 1, &alt, 0)) < 0)
632 return ret;
633 if (!base || !alt)
634 return AVERROR_BUG;
635
637 if (ret < 0)
638 return ret;
639
640 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
641 if (!out)
642 return AVERROR(ENOMEM);
644 out->pts = av_rescale_q(fs->pts, fs->time_base, outlink->time_base);
645 av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data,
647
648 out->color_trc = AVCOL_TRC_UNSPECIFIED;
649 out->color_primaries = AVCOL_PRI_UNSPECIFIED;
650 out->colorspace = AVCOL_SPC_UNSPECIFIED;
651 out->color_range = AVCOL_RANGE_JPEG;
652
653 ThreadData td = {
654 .out = out,
655 .base = base,
656 .alt = alt,
657 };
658
659 if (!s->sign) { /* no-op */
660 for (int i = 0; i < s->nb_channels; i++)
661 memset(out->data[i], 0, out->height * out->linesize[i]);
662 goto skip;
663 }
664
665 const int nb_jobs = FFMIN(outlink->h, s->nb_threads);
667 &td, NULL, nb_jobs);
668 if (ret < 0)
669 goto fail;
670
671 if (s->measure) {
672 choose_quant_params(ctx, out, nb_jobs);
673 ret = ff_filter_execute(ctx, slice_quant, &td, NULL, nb_jobs);
674 if (ret < 0)
675 goto fail;
676 }
677
678skip:;
680 params = av_gain_map_params_create_side_data(&out->side_data, &out->nb_side_data);
681 if (!params) {
682 ret = AVERROR(ENOMEM);
683 goto fail;
684 }
685
686 memcpy(params, s->params, s->params_size);
688 return AVERROR_BUG; /* should never happen */
689
690 return ff_filter_frame(outlink, out);
691
692fail:
694 return ret;
695}
696
697static int config_output(AVFilterLink *outlink)
698{
699 AVFilterContext *ctx = outlink->src;
700 GainMapContext *s = ctx->priv;
701 AVFilterLink *base = ctx->inputs[0];
702 AVFilterLink *alt = ctx->inputs[1];
703 int ret;
704
705 if (base->w != alt->w || base->h != alt->h) {
707 "Input dimensions must match (%dx%d != %dx%d)\n",
708 base->w, base->h, alt->w, alt->h);
709 return AVERROR(EINVAL);
710 }
711
712 outlink->w = base->w;
713 outlink->h = base->h;
715 outlink->color_range = AVCOL_RANGE_JPEG;
716
717 s->nb_threads = ff_filter_get_nb_threads(ctx);
718 s->slice_min = av_calloc(s->nb_threads, sizeof(*s->slice_min));
719 s->slice_max = av_calloc(s->nb_threads, sizeof(*s->slice_max));
720 s->slice_sum = av_calloc(s->nb_threads, sizeof(*s->slice_sum));
721 if (!s->slice_min || !s->slice_max || !s->slice_sum)
722 return AVERROR(ENOMEM);
723
725 if (ret < 0)
726 return ret;
727
728 s->fs.on_event = process_frame;
729 return ff_framesync_configure(&s->fs);
730}
731
733{
734 GainMapContext *s = ctx->priv;
735 return ff_framesync_activate(&s->fs);
736}
737
739{
740 GainMapContext *s = ctx->priv;
742 av_freep(&s->slice_min);
743 av_freep(&s->slice_max);
744 av_freep(&s->slice_sum);
745 av_freep(&s->params);
746}
747
748static const AVFilterPad gainmap_inputs[] = {
749 {
750 .name = "base",
751 .type = AVMEDIA_TYPE_VIDEO,
752 },
753 {
754 .name = "alternate",
755 .type = AVMEDIA_TYPE_VIDEO,
756 },
757};
758
759static const AVFilterPad gainmap_outputs[] = {
760 {
761 .name = "default",
762 .type = AVMEDIA_TYPE_VIDEO,
763 .config_props = config_output,
764 },
765};
766
768 .p.name = "gainmap",
769 .p.description = NULL_IF_CONFIG_SMALL("Generate a gain map from a base/alternate pair."),
770 .p.priv_class = &gainmap_class,
772 .preinit = gainmap_framesync_preinit,
773 .priv_size = sizeof(GainMapContext),
774 .init = init,
775 .uninit = uninit,
780};
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:97
SwsAArch64OpImplParams params
Definition ops.c:52
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition aeval.c:246
#define MEASURE_ALL
const FFFilter ff_vf_gainmap
Definition vf_gainmap.c:767
#define log2(x)
Definition math.h:26
static FILE * out
static AVFormatContext * ctx
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1079
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition avfilter.c:1721
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition avfilter.c:857
Main libavfilter public API header.
static void BS_FUNC skip(BSCTX *bc, unsigned int n)
Skip n bits in the buffer.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define fs(width, name, subs,...)
Definition cbs_vp9.c:200
#define rnd
Definition checkasm.h:140
#define FLAGS
Definition cmdutils.c:596
#define av_clipd
Definition common.h:148
#define av_clipf
Definition common.h:145
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
Colorspace value utility functions for libavutil.
static __device__ float ceil(float a)
static __device__ float floor(float a)
#define min(a, b)
#define max(a, b)
static AVFrame * frame
float fminf(float, float)
double fmax(double, double)
float fmaxf(float, float)
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:613
static const uint8_t gbr_order[4]
Definition exrenc.c:59
static const char * unknown_if_null(const char *str)
int ret
Definition ffplay.c:391
static av_always_inline int process_frame(AVTextFormatContext *tfc, InputFile *ifile, AVFrame *frame, const AVPacket *pkt, int *packet_new)
Definition ffprobe.c:1713
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add ref as a new reference to formats.
Definition formats.c:776
AVFilterFormats * ff_make_formats_list_singleton(int fmt)
Equivalent to ff_make_format_list({const int[]}{ fmt, -1 })
Definition formats.c:605
int ff_set_common_formats2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, AVFilterFormats *formats)
Definition formats.c:1200
int ff_framesync_configure(FFFrameSync *fs)
Configure a frame sync structure.
Definition framesync.c:137
int ff_framesync_activate(FFFrameSync *fs)
Examine the frames in the filter's input and try to produce output.
Definition framesync.c:352
int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe, unsigned get)
Get the current frame in an input.
Definition framesync.c:269
int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent)
Initialize a frame sync structure for dualinput.
Definition framesync.c:372
void ff_framesync_uninit(FFFrameSync *fs)
Free all memory currently allocated.
Definition framesync.c:301
#define FRAMESYNC_DEFINE_CLASS(name, context, field)
Definition framesync.h:352
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_RATIONAL
Underlying C type is AVRational.
Definition opt.h:279
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition avfilter.h:172
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition error.h:52
#define AVERROR(e)
Definition error.h:45
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition frame.c:662
void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, int props)
Remove and free all side data instances that match any of the given side data properties.
Definition side_data.c:124
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:65
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:602
@ AV_SIDE_DATA_PROP_COLOR_DEPENDENT
Side data depends on the video color space.
Definition frame.h:368
@ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA
Mastering display metadata associated with a video frame.
Definition frame.h:120
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const AVColorPrimariesDesc * av_csp_primaries_desc_from_id(enum AVColorPrimaries prm)
Retrieves a complete gamut description from an enum constant describing the color primaries.
Definition csp.c:95
void(* av_csp_eotf_function)(double Lw, double Lb, double c[3])
Function pointer representing an ITU EOTF transfer for a given reference display configuration.
Definition csp.h:178
av_csp_eotf_function av_csp_itu_eotf(enum AVColorTransferCharacteristic trc)
Returns the ITU EOTF corresponding to a given TRC.
Definition csp.c:658
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition rational.c:35
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition rational.h:104
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition rational.h:89
AVRounding
Rounding methods.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AV_ROUND_DOWN
Round toward -infinity.
@ AV_ROUND_UP
Round toward +infinity.
@ AV_ROUND_NEAR_INF
Round to nearest and halfway cases away from zero.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int a
static av_always_inline void scale(vec_s32 res[4], vec_s16 res_packed[2], const int shift)
#define r
Definition input.c:42
#define b
Definition input.c:43
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int config_output(AVBitStreamFilterLink *outlink)
unsigned offset
Definition libaomenc.c:763
const char * arg
Definition jacosubdec.c:66
void ff_matrix_mul_3x3(double dst[3][3], const double src1[3][3], const double src2[3][3])
Definition colorspace.c:54
void ff_fill_rgb2xyz_table(const AVPrimaryCoefficients *coeffs, const AVWhitepointCoefficients *wp, double rgb2xyz[3][3])
Definition colorspace.c:79
void ff_matrix_invert_3x3(const double in[3][3], double out[3][3])
Definition colorspace.c:27
#define FILTER_INPUTS(array)
Definition filters.h:279
#define FILTER_OUTPUTS(array)
Definition filters.h:280
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition filters.h:789
#define FILTER_QUERY_FUNC2(func)
Definition filters.h:256
#define av_always_inline
Definition attributes.h:72
#define av_cold
Definition attributes.h:117
int av_gain_map_params_validate(const AVGainMapParams *p)
Returns >= 0 if the given AVGainMapParams struct contains valid data; or a negative AVERROR otherwise...
Definition gain_map.c:47
AVGainMapParams * av_gain_map_params_alloc(size_t *size)
Allocate an AVGainMapParams structure and initialize it to default values.
Definition gain_map.c:224
AVGainMapParams * av_gain_map_params_create_side_data(AVFrameSideData ***fsd, int *nb_sd)
Allocate and add an AVGainMapParams structure to an existing AVFrameSideData array as AV_FRAME_DATA_G...
Definition gain_map.c:238
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:97
void av_log_once(void *avcl, int initial_level, int subsequent_level, int *state, const char *fmt,...)
Definition log.c:456
#define FFSWAP(type, a, b)
Definition macros.h:52
#define FFMIN(a, b)
Definition macros.h:49
#define FFDIFFSIGN(x, y)
Comparator.
Definition macros.h:45
#define NAN
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:370
Memory handling functions.
AVOptions.
const char * av_color_transfer_name(enum AVColorTransferCharacteristic transfer)
Definition pixdesc.c:3851
const char * av_color_primaries_name(enum AVColorPrimaries primaries)
Definition pixdesc.c:3818
#define AV_PIX_FMT_GBRPF32
Definition pixfmt.h:587
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:792
#define AV_PIX_FMT_GRAYF32
Definition pixfmt.h:591
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AVCOL_PRI_UNSPECIFIED
Definition pixfmt.h:650
AVColorTransferCharacteristic
Color Transfer Characteristic.
Definition pixfmt.h:677
@ AVCOL_TRC_SMPTE170M
also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC
Definition pixfmt.h:684
@ AVCOL_TRC_SMPTE2084
SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems.
Definition pixfmt.h:694
@ AVCOL_TRC_GAMMA22
also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
Definition pixfmt.h:682
@ AVCOL_TRC_BT1361_ECG
ITU-R BT1361 Extended Colour Gamut.
Definition pixfmt.h:690
@ AVCOL_TRC_SMPTE240M
Definition pixfmt.h:685
@ AVCOL_TRC_IEC61966_2_4
IEC 61966-2-4.
Definition pixfmt.h:689
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition pixfmt.h:686
@ AVCOL_TRC_GAMMA28
also ITU-R BT470BG
Definition pixfmt.h:683
@ AVCOL_TRC_ARIB_STD_B67
ARIB STD-B67, known as "Hybrid log-gamma".
Definition pixfmt.h:698
@ AVCOL_TRC_SMPTE428
SMPTE ST 428-1.
Definition pixfmt.h:696
@ AVCOL_TRC_BT2020_12
ITU-R BT2020 for 12-bit system.
Definition pixfmt.h:693
@ AVCOL_TRC_IEC61966_2_1
IEC 61966-2-1 (sRGB or sYCC)
Definition pixfmt.h:691
@ AVCOL_TRC_BT2020_10
ITU-R BT2020 for 10-bit system.
Definition pixfmt.h:692
@ AVCOL_TRC_UNSPECIFIED
Definition pixfmt.h:680
@ AVCOL_TRC_BT709
also ITU-R BT1361
Definition pixfmt.h:679
@ AVCOL_SPC_UNSPECIFIED
Definition pixfmt.h:714
formats
Definition signature.h:47
AVRational y
Definition csp.h:57
Describe the class of an AVClass context structure.
Definition log.h:76
Struct that contains both white point location and primaries location, providing the complete descrip...
Definition csp.h:78
AVWhitepointCoefficients wp
Definition csp.h:79
AVPrimaryCoefficients prim
Definition csp.h:80
An instance of a filter.
Definition avfilter.h:279
Lists of formats / etc.
Definition avfilter.h:120
A filter pad used for either input or output.
Definition filters.h:40
Structure to hold side data for an AVFrame.
Definition frame.h:334
uint8_t * data
Definition frame.h:336
This structure describes decoded (raw) audio or video data.
Definition frame.h:479
Parameters describing how to combine a gain map rendition with its base rendition to recover the alte...
Definition gain_map.h:39
Mastering display metadata capable of representing the color volume of the display used to master the...
AVRational max_luminance
Max luminance of mastering display (cd/m^2).
int has_luminance
Flag indicating whether the luminance (min_ and max_) have been set.
AVOption.
Definition opt.h:428
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
Frame sync structure.
Definition framesync.h:168
float rgb2y[3]
Definition vf_gainmap.c:98
enum GainMapMeasure measure
Definition vf_gainmap.c:110
double(* slice_sum)[3]
Definition vf_gainmap.c:109
AVRational gamma
Definition vf_gainmap.c:83
float(* slice_min)[3]
Definition vf_gainmap.c:107
FFFrameSync fs
Definition vf_gainmap.c:76
GainMapEOTF base_eotf
Definition vf_gainmap.c:96
float rgb2rgb[3][3]
Definition vf_gainmap.c:99
AVRational base_nits
Definition vf_gainmap.c:86
size_t params_size
Definition vf_gainmap.c:114
AVRational base_offset
Definition vf_gainmap.c:84
AVRational gain_max
Definition vf_gainmap.c:82
float(* slice_max)[3]
Definition vf_gainmap.c:108
AVRational gain_min
Definition vf_gainmap.c:81
float quant_scale[3]
Definition vf_gainmap.c:102
AVRational alt_nits
Definition vf_gainmap.c:87
GainMapEOTF alt_eotf
Definition vf_gainmap.c:97
AVRational alt_offset
Definition vf_gainmap.c:85
AVGainMapParams * params
Definition vf_gainmap.c:113
float quant_gamma[3]
Definition vf_gainmap.c:104
float quant_offset[3]
Definition vf_gainmap.c:103
double Lw
Definition vf_gainmap.c:68
av_csp_eotf_function eotf
Definition vf_gainmap.c:67
float lut[GAINMAP_LUT_SIZE+1]
Definition vf_gainmap.c:71
enum AVColorTransferCharacteristic trc
Definition vf_gainmap.c:66
Used for passing data between threads.
Definition v210dec.c:35
AVFrame * out
const AVFrame * base
Definition vf_gainmap.c:119
const AVFrame * alt
Definition vf_gainmap.c:119
Definition swscale.c:85
Definition rpzaenc.c:60
#define av_freep(p)
#define av_log(a,...)
#define alt(var)
#define src
Definition vp8dsp.c:248
#define width
Definition dsp.h:99
static const float xyz2rgb[3][3]
Definition tiff.c:1912
const char * g
Definition vf_curves.c:128
static void setup_range(AVFilterContext *ctx, int ch, AVRational min, AVRational max)
Definition vf_gainmap.c:162
static int slice_gain(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_gainmap.c:532
static double frame_luminance(const AVFrame *frame)
Definition vf_gainmap.c:253
GainMapMeasure
Definition vf_gainmap.c:57
@ MEASURE_MIN
Definition vf_gainmap.c:58
@ MEASURE_GAMMA
Definition vf_gainmap.c:60
@ MEASURE_MAX
Definition vf_gainmap.c:59
@ MEASURE_RANGE
Definition vf_gainmap.c:61
static int slice_quant(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_gainmap.c:542
static const AVFilterPad gainmap_outputs[]
Definition vf_gainmap.c:759
static int slice_gain_quant(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_gainmap.c:537
static const AVOption gainmap_options[]
Definition vf_gainmap.c:125
static const char * unknown_if_null(const char *s)
Definition vf_gainmap.c:312
static int setup_colorspace(AVFilterContext *ctx, const AVFrame *base, const AVFrame *alt)
Definition vf_gainmap.c:318
#define GAINMAP_LUT_SIZE
Definition vf_gainmap.c:70
GainMapColorspace
Definition vf_gainmap.c:44
@ GAINMAP_CSP_ALT
apply it in the alternate rendition's space
Definition vf_gainmap.c:46
@ GAINMAP_CSP_NB
Definition vf_gainmap.c:47
@ GAINMAP_CSP_BASE
apply the map in the base rendition's space
Definition vf_gainmap.c:45
static av_always_inline float quantize(float gain, float scale, float offset, float gamma)
Definition vf_gainmap.c:395
static av_always_inline int slice_internal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, int quant)
Definition vf_gainmap.c:442
#define SDR_DIFFUSE_WHITE
Definition vf_gainmap.c:42
static void update_eotf(GainMapEOTF *tf, enum AVColorTransferCharacteristic trc, av_csp_eotf_function eotf, double Lw)
Definition vf_gainmap.c:271
GainMapMode
Definition vf_gainmap.c:50
@ GAINMAP_RGB
one channel per component
Definition vf_gainmap.c:51
@ GAINMAP_MODE_NB
Definition vf_gainmap.c:54
@ GAINMAP_LUMA
single channel, from the luminance
Definition vf_gainmap.c:52
@ GAINMAP_MAXRGB
single channel, from max(R,G,B)
Definition vf_gainmap.c:53
static int query_formats(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
Definition vf_gainmap.c:234
static int activate(AVFilterContext *ctx)
Definition vf_gainmap.c:732
static av_cold void uninit(AVFilterContext *ctx)
Definition vf_gainmap.c:738
static void setup_gamma(AVFilterContext *ctx, int ch, AVRational gamma)
Definition vf_gainmap.c:181
static void choose_quant_params(AVFilterContext *ctx, const AVFrame *out, int nb_jobs)
Definition vf_gainmap.c:573
#define OFFSET(x)
Definition vf_gainmap.c:122
static int config_output(AVFilterLink *outlink)
Definition vf_gainmap.c:697
#define GAIN(a, b)
static AVRational quantq(double x, enum AVRounding rnd)
Definition vf_gainmap.c:146
static av_always_inline void get_pixel(const GainMapContext *s, float dst[3], const float *restrict const src[3], int x, int alt)
Definition vf_gainmap.c:402
static int process_frame(FFFrameSync *fs)
Definition vf_gainmap.c:622
static const AVFilterPad gainmap_inputs[]
Definition vf_gainmap.c:748
static float mean(const float *input, int size)
Definition vf_nnedi.c:792
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:120
static const uint8_t quant[64]
Definition vmixdec.c:71
uint8_t base
Definition vp3data.h:128
static double c[64]