FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_lensfun.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 by Andrew Zabolotny (author of lensfun, from which this filter derives from)
3  * Copyright (C) 2018 Stephen Seo
4  *
5  * This file is part of FFmpeg.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 /**
22  * @file
23  * Lensfun filter, applies lens correction with parameters from the lensfun database
24  *
25  * @see https://lensfun.sourceforge.net/
26  */
27 
28 #include <float.h>
29 #include <math.h>
30 
31 #include "libavutil/avassert.h"
32 #include "libavutil/imgutils.h"
33 #include "libavutil/opt.h"
34 #include "libswscale/swscale.h"
35 #include "avfilter.h"
36 #include "formats.h"
37 #include "internal.h"
38 #include "video.h"
39 
40 #include <lensfun.h>
41 
42 #define LANCZOS_RESOLUTION 256
43 
44 enum Mode {
45  VIGNETTING = 0x1,
48 };
49 
54 };
55 
56 typedef struct VignettingThreadData {
57  int width, height;
61  lfModifier *modifier;
63 
65  int width, height;
66  const float *distortion_coords;
67  const uint8_t *data_in;
70  const float *interpolation;
71  int mode;
74 
75 typedef struct LensfunContext {
76  const AVClass *class;
77  const char *make, *model, *lens_model;
78  int mode;
79  float focal_length;
80  float aperture;
83  int reverse;
85 
87  float *interpolation;
88 
89  lfLens *lens;
90  lfCamera *camera;
91  lfModifier *modifier;
93 
94 #define OFFSET(x) offsetof(LensfunContext, x)
95 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
96 static const AVOption lensfun_options[] = {
97  { "make", "set camera maker", OFFSET(make), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
98  { "model", "set camera model", OFFSET(model), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
99  { "lens_model", "set lens model", OFFSET(lens_model), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
100  { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=GEOMETRY_DISTORTION}, 0, VIGNETTING | GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION, FLAGS, "mode" },
101  { "vignetting", "fix lens vignetting", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING}, 0, 0, FLAGS, "mode" },
102  { "geometry", "correct geometry distortion", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRY_DISTORTION}, 0, 0, FLAGS, "mode" },
103  { "subpixel", "fix chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" },
104  { "vig_geo", "fix lens vignetting and correct geometry distortion", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | GEOMETRY_DISTORTION}, 0, 0, FLAGS, "mode" },
105  { "vig_subpixel", "fix lens vignetting and chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" },
106  { "distortion", "correct geometry distortion and chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" },
107  { "all", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" },
108  { "focal_length", "focal length of video (zoom; constant for the duration of the use of this filter)", OFFSET(focal_length), AV_OPT_TYPE_FLOAT, {.dbl=18}, 0.0, DBL_MAX, FLAGS },
109  { "aperture", "aperture (constant for the duration of the use of this filter)", OFFSET(aperture), AV_OPT_TYPE_FLOAT, {.dbl=3.5}, 0.0, DBL_MAX, FLAGS },
110  { "focus_distance", "focus distance (constant for the duration of the use of this filter)", OFFSET(focus_distance), AV_OPT_TYPE_FLOAT, {.dbl=1000.0f}, 0.0, DBL_MAX, FLAGS },
111  { "target_geometry", "target geometry of the lens correction (only when geometry correction is enabled)", OFFSET(target_geometry), AV_OPT_TYPE_INT, {.i64=LF_RECTILINEAR}, 0, INT_MAX, FLAGS, "lens_geometry" },
112  { "rectilinear", "rectilinear lens (default)", 0, AV_OPT_TYPE_CONST, {.i64=LF_RECTILINEAR}, 0, 0, FLAGS, "lens_geometry" },
113  { "fisheye", "fisheye lens", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE}, 0, 0, FLAGS, "lens_geometry" },
114  { "panoramic", "panoramic (cylindrical)", 0, AV_OPT_TYPE_CONST, {.i64=LF_PANORAMIC}, 0, 0, FLAGS, "lens_geometry" },
115  { "equirectangular", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=LF_EQUIRECTANGULAR}, 0, 0, FLAGS, "lens_geometry" },
116  { "fisheye_orthographic", "orthographic fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_ORTHOGRAPHIC}, 0, 0, FLAGS, "lens_geometry" },
117  { "fisheye_stereographic", "stereographic fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_STEREOGRAPHIC}, 0, 0, FLAGS, "lens_geometry" },
118  { "fisheye_equisolid", "equisolid fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_EQUISOLID}, 0, 0, FLAGS, "lens_geometry" },
119  { "fisheye_thoby", "fisheye as measured by thoby", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_THOBY}, 0, 0, FLAGS, "lens_geometry" },
120  { "reverse", "Does reverse correction (regular image to lens distorted)", OFFSET(reverse), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
121  { "interpolation", "Type of interpolation", OFFSET(interpolation_type), AV_OPT_TYPE_INT, {.i64=LINEAR}, 0, LANCZOS, FLAGS, "interpolation" },
122  { "nearest", NULL, 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, "interpolation" },
123  { "linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "interpolation" },
124  { "lanczos", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, "interpolation" },
125  { NULL }
126 };
127 
128 AVFILTER_DEFINE_CLASS(lensfun);
129 
131 {
132  LensfunContext *lensfun = ctx->priv;
133  lfDatabase *db;
134  const lfCamera **cameras;
135  const lfLens **lenses;
136 
137  if (!lensfun->make) {
138  av_log(ctx, AV_LOG_FATAL, "Option \"make\" not specified\n");
139  return AVERROR(EINVAL);
140  } else if (!lensfun->model) {
141  av_log(ctx, AV_LOG_FATAL, "Option \"model\" not specified\n");
142  return AVERROR(EINVAL);
143  } else if (!lensfun->lens_model) {
144  av_log(ctx, AV_LOG_FATAL, "Option \"lens_model\" not specified\n");
145  return AVERROR(EINVAL);
146  }
147 
148  lensfun->lens = lf_lens_new();
149  lensfun->camera = lf_camera_new();
150 
151  db = lf_db_new();
152  if (lf_db_load(db) != LF_NO_ERROR) {
153  lf_db_destroy(db);
154  av_log(ctx, AV_LOG_FATAL, "Failed to load lensfun database\n");
155  return AVERROR_INVALIDDATA;
156  }
157 
158  cameras = lf_db_find_cameras(db, lensfun->make, lensfun->model);
159  if (cameras && *cameras) {
160  lf_camera_copy(lensfun->camera, *cameras);
161  av_log(ctx, AV_LOG_INFO, "Using camera %s\n", lensfun->camera->Model);
162  } else {
163  lf_free(cameras);
164  lf_db_destroy(db);
165  av_log(ctx, AV_LOG_FATAL, "Failed to find camera in lensfun database\n");
166  return AVERROR_INVALIDDATA;
167  }
168  lf_free(cameras);
169 
170  lenses = lf_db_find_lenses_hd(db, lensfun->camera, NULL, lensfun->lens_model, 0);
171  if (lenses && *lenses) {
172  lf_lens_copy(lensfun->lens, *lenses);
173  av_log(ctx, AV_LOG_INFO, "Using lens %s\n", lensfun->lens->Model);
174  } else {
175  lf_free(lenses);
176  lf_db_destroy(db);
177  av_log(ctx, AV_LOG_FATAL, "Failed to find lens in lensfun database\n");
178  return AVERROR_INVALIDDATA;
179  }
180  lf_free(lenses);
181 
182  lf_db_destroy(db);
183  return 0;
184 }
185 
187 {
188  // Some of the functions provided by lensfun require pixels in RGB format
189  static const enum AVPixelFormat fmts[] = {AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE};
190  AVFilterFormats *fmts_list = ff_make_format_list(fmts);
191  return ff_set_common_formats(ctx, fmts_list);
192 }
193 
194 static float lanczos_kernel(float x)
195 {
196  if (x == 0.0f) {
197  return 1.0f;
198  } else if (x > -2.0f && x < 2.0f) {
199  return (2.0f * sin(M_PI * x) * sin(M_PI / 2.0f * x)) / (M_PI * M_PI * x * x);
200  } else {
201  return 0.0f;
202  }
203 }
204 
205 static int config_props(AVFilterLink *inlink)
206 {
207  AVFilterContext *ctx = inlink->dst;
208  LensfunContext *lensfun = ctx->priv;
209  int index;
210  float a;
211  int lensfun_mode = 0;
212 
213  if (!lensfun->modifier) {
214  if (lensfun->camera && lensfun->lens) {
215  lensfun->modifier = lf_modifier_new(lensfun->lens,
216  lensfun->camera->CropFactor,
217  inlink->w,
218  inlink->h);
219  if (lensfun->mode & VIGNETTING)
220  lensfun_mode |= LF_MODIFY_VIGNETTING;
221  if (lensfun->mode & GEOMETRY_DISTORTION)
222  lensfun_mode |= LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE;
223  if (lensfun->mode & SUBPIXEL_DISTORTION)
224  lensfun_mode |= LF_MODIFY_TCA;
225  lf_modifier_initialize(lensfun->modifier,
226  lensfun->lens,
227  LF_PF_U8,
228  lensfun->focal_length,
229  lensfun->aperture,
230  lensfun->focus_distance,
231  0.0,
232  lensfun->target_geometry,
233  lensfun_mode,
234  lensfun->reverse);
235  } else {
236  // lensfun->camera and lensfun->lens should have been initialized
237  return AVERROR_BUG;
238  }
239  }
240 
241  if (!lensfun->distortion_coords) {
242  if (lensfun->mode & SUBPIXEL_DISTORTION) {
243  lensfun->distortion_coords = av_malloc_array(inlink->w * inlink->h, sizeof(float) * 2 * 3);
244  if (!lensfun->distortion_coords)
245  return AVERROR(ENOMEM);
246  if (lensfun->mode & GEOMETRY_DISTORTION) {
247  // apply both geometry and subpixel distortion
248  lf_modifier_apply_subpixel_geometry_distortion(lensfun->modifier,
249  0, 0,
250  inlink->w, inlink->h,
251  lensfun->distortion_coords);
252  } else {
253  // apply only subpixel distortion
254  lf_modifier_apply_subpixel_distortion(lensfun->modifier,
255  0, 0,
256  inlink->w, inlink->h,
257  lensfun->distortion_coords);
258  }
259  } else if (lensfun->mode & GEOMETRY_DISTORTION) {
260  lensfun->distortion_coords = av_malloc_array(inlink->w * inlink->h, sizeof(float) * 2);
261  if (!lensfun->distortion_coords)
262  return AVERROR(ENOMEM);
263  // apply only geometry distortion
264  lf_modifier_apply_geometry_distortion(lensfun->modifier,
265  0, 0,
266  inlink->w, inlink->h,
267  lensfun->distortion_coords);
268  }
269  }
270 
271  if (!lensfun->interpolation)
272  if (lensfun->interpolation_type == LANCZOS) {
273  lensfun->interpolation = av_malloc_array(LANCZOS_RESOLUTION, sizeof(float) * 4);
274  if (!lensfun->interpolation)
275  return AVERROR(ENOMEM);
276  for (index = 0; index < 4 * LANCZOS_RESOLUTION; ++index) {
277  if (index == 0) {
278  lensfun->interpolation[index] = 1.0f;
279  } else {
280  a = sqrtf((float)index / LANCZOS_RESOLUTION);
281  lensfun->interpolation[index] = lanczos_kernel(a);
282  }
283  }
284  }
285 
286  return 0;
287 }
288 
289 static int vignetting_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
290 {
292  const int slice_start = thread_data->height * jobnr / nb_jobs;
293  const int slice_end = thread_data->height * (jobnr + 1) / nb_jobs;
294 
295  lf_modifier_apply_color_modification(thread_data->modifier,
296  thread_data->data_in + slice_start * thread_data->linesize_in,
297  0,
298  slice_start,
299  thread_data->width,
300  slice_end - slice_start,
301  thread_data->pixel_composition,
302  thread_data->linesize_in);
303 
304  return 0;
305 }
306 
307 static float square(float x)
308 {
309  return x * x;
310 }
311 
312 static int distortion_correction_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
313 {
315  const int slice_start = thread_data->height * jobnr / nb_jobs;
316  const int slice_end = thread_data->height * (jobnr + 1) / nb_jobs;
317 
318  int x, y, i, j, rgb_index;
319  float interpolated, new_x, new_y, d, norm;
320  int new_x_int, new_y_int;
321  for (y = slice_start; y < slice_end; ++y)
322  for (x = 0; x < thread_data->width; ++x)
323  for (rgb_index = 0; rgb_index < 3; ++rgb_index) {
324  if (thread_data->mode & SUBPIXEL_DISTORTION) {
325  // subpixel (and possibly geometry) distortion correction was applied, correct distortion
326  switch(thread_data->interpolation_type) {
327  case NEAREST:
328  new_x_int = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2] + 0.5f;
329  new_y_int = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1] + 0.5f;
330  if (new_x_int < 0 || new_x_int >= thread_data->width || new_y_int < 0 || new_y_int >= thread_data->height) {
331  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
332  } else {
333  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = thread_data->data_in[new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in];
334  }
335  break;
336  case LINEAR:
337  interpolated = 0.0f;
338  new_x = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2];
339  new_x_int = new_x;
340  new_y = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1];
341  new_y_int = new_y;
342  if (new_x_int < 0 || new_x_int + 1 >= thread_data->width || new_y_int < 0 || new_y_int + 1 >= thread_data->height) {
343  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
344  } else {
345  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] =
346  thread_data->data_in[ new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y_int + 1 - new_y)
347  + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x - new_x_int) * (new_y_int + 1 - new_y)
348  + thread_data->data_in[ new_x_int * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y - new_y_int)
349  + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x - new_x_int) * (new_y - new_y_int);
350  }
351  break;
352  case LANCZOS:
353  interpolated = 0.0f;
354  norm = 0.0f;
355  new_x = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2];
356  new_x_int = new_x;
357  new_y = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1];
358  new_y_int = new_y;
359  for (j = 0; j < 4; ++j)
360  for (i = 0; i < 4; ++i) {
361  if (new_x_int + i - 2 < 0 || new_x_int + i - 2 >= thread_data->width || new_y_int + j - 2 < 0 || new_y_int + j - 2 >= thread_data->height)
362  continue;
363  d = square(new_x - (new_x_int + i - 2)) * square(new_y - (new_y_int + j - 2));
364  if (d >= 4.0f)
365  continue;
366  d = thread_data->interpolation[(int)(d * LANCZOS_RESOLUTION)];
367  norm += d;
368  interpolated += thread_data->data_in[(new_x_int + i - 2) * 3 + rgb_index + (new_y_int + j - 2) * thread_data->linesize_in] * d;
369  }
370  if (norm == 0.0f) {
371  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
372  } else {
373  interpolated /= norm;
374  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = interpolated < 0.0f ? 0.0f : interpolated > 255.0f ? 255.0f : interpolated;
375  }
376  break;
377  }
378  } else if (thread_data->mode & GEOMETRY_DISTORTION) {
379  // geometry distortion correction was applied, correct distortion
380  switch(thread_data->interpolation_type) {
381  case NEAREST:
382  new_x_int = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2] + 0.5f;
383  new_y_int = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2 + 1] + 0.5f;
384  if (new_x_int < 0 || new_x_int >= thread_data->width || new_y_int < 0 || new_y_int >= thread_data->height) {
385  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
386  } else {
387  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = thread_data->data_in[new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in];
388  }
389  break;
390  case LINEAR:
391  interpolated = 0.0f;
392  new_x = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2];
393  new_x_int = new_x;
394  new_y = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2 + 1];
395  new_y_int = new_y;
396  if (new_x_int < 0 || new_x_int + 1 >= thread_data->width || new_y_int < 0 || new_y_int + 1 >= thread_data->height) {
397  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
398  } else {
399  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] =
400  thread_data->data_in[ new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y_int + 1 - new_y)
401  + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x - new_x_int) * (new_y_int + 1 - new_y)
402  + thread_data->data_in[ new_x_int * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y - new_y_int)
403  + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x - new_x_int) * (new_y - new_y_int);
404  }
405  break;
406  case LANCZOS:
407  interpolated = 0.0f;
408  norm = 0.0f;
409  new_x = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2];
410  new_x_int = new_x;
411  new_y = thread_data->distortion_coords[x * 2 + 1 + y * thread_data->width * 2];
412  new_y_int = new_y;
413  for (j = 0; j < 4; ++j)
414  for (i = 0; i < 4; ++i) {
415  if (new_x_int + i - 2 < 0 || new_x_int + i - 2 >= thread_data->width || new_y_int + j - 2 < 0 || new_y_int + j - 2 >= thread_data->height)
416  continue;
417  d = square(new_x - (new_x_int + i - 2)) * square(new_y - (new_y_int + j - 2));
418  if (d >= 4.0f)
419  continue;
420  d = thread_data->interpolation[(int)(d * LANCZOS_RESOLUTION)];
421  norm += d;
422  interpolated += thread_data->data_in[(new_x_int + i - 2) * 3 + rgb_index + (new_y_int + j - 2) * thread_data->linesize_in] * d;
423  }
424  if (norm == 0.0f) {
425  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
426  } else {
427  interpolated /= norm;
428  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = interpolated < 0.0f ? 0.0f : interpolated > 255.0f ? 255.0f : interpolated;
429  }
430  break;
431  }
432  } else {
433  // no distortion correction was applied
434  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = thread_data->data_in[x * 3 + rgb_index + y * thread_data->linesize_in];
435  }
436  }
437 
438  return 0;
439 }
440 
441 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
442 {
443  AVFilterContext *ctx = inlink->dst;
444  LensfunContext *lensfun = ctx->priv;
445  AVFilterLink *outlink = ctx->outputs[0];
446  AVFrame *out;
447  VignettingThreadData vignetting_thread_data;
448  DistortionCorrectionThreadData distortion_correction_thread_data;
449 
450  if (lensfun->mode & VIGNETTING) {
452 
453  vignetting_thread_data = (VignettingThreadData) {
454  .width = inlink->w,
455  .height = inlink->h,
456  .data_in = in->data[0],
457  .linesize_in = in->linesize[0],
458  .pixel_composition = LF_CR_3(RED, GREEN, BLUE),
459  .modifier = lensfun->modifier
460  };
461 
462  ctx->internal->execute(ctx,
464  &vignetting_thread_data,
465  NULL,
466  FFMIN(outlink->h, ctx->graph->nb_threads));
467  }
468 
469  if (lensfun->mode & (GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION)) {
470  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
471  if (!out) {
472  av_frame_free(&in);
473  return AVERROR(ENOMEM);
474  }
475  av_frame_copy_props(out, in);
476 
477  distortion_correction_thread_data = (DistortionCorrectionThreadData) {
478  .width = inlink->w,
479  .height = inlink->h,
480  .distortion_coords = lensfun->distortion_coords,
481  .data_in = in->data[0],
482  .data_out = out->data[0],
483  .linesize_in = in->linesize[0],
484  .linesize_out = out->linesize[0],
485  .interpolation = lensfun->interpolation,
486  .mode = lensfun->mode,
487  .interpolation_type = lensfun->interpolation_type
488  };
489 
490  ctx->internal->execute(ctx,
492  &distortion_correction_thread_data,
493  NULL,
494  FFMIN(outlink->h, ctx->graph->nb_threads));
495 
496  av_frame_free(&in);
497  return ff_filter_frame(outlink, out);
498  } else {
499  return ff_filter_frame(outlink, in);
500  }
501 }
502 
504 {
505  LensfunContext *lensfun = ctx->priv;
506 
507  if (lensfun->camera)
508  lf_camera_destroy(lensfun->camera);
509  if (lensfun->lens)
510  lf_lens_destroy(lensfun->lens);
511  if (lensfun->modifier)
512  lf_modifier_destroy(lensfun->modifier);
513  av_freep(&lensfun->distortion_coords);
514  av_freep(&lensfun->interpolation);
515 }
516 
517 static const AVFilterPad lensfun_inputs[] = {
518  {
519  .name = "default",
520  .type = AVMEDIA_TYPE_VIDEO,
521  .config_props = config_props,
522  .filter_frame = filter_frame,
523  },
524  { NULL }
525 };
526 
527 static const AVFilterPad lensfun_outputs[] = {
528  {
529  .name = "default",
530  .type = AVMEDIA_TYPE_VIDEO,
531  },
532  { NULL }
533 };
534 
536  .name = "lensfun",
537  .description = NULL_IF_CONFIG_SMALL("Apply correction to an image based on info derived from the lensfun database."),
538  .priv_size = sizeof(LensfunContext),
539  .init = init,
540  .uninit = uninit,
542  .inputs = lensfun_inputs,
543  .outputs = lensfun_outputs,
544  .priv_class = &lensfun_class,
546 };
#define NULL
Definition: coverity.c:32
#define OFFSET(x)
Definition: vf_lensfun.c:94
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:226
AVOption.
Definition: opt.h:246
misc image utilities
Main libavfilter public API header.
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
static const AVFilterPad lensfun_outputs[]
Definition: vf_lensfun.c:527
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
struct AVFilterGraph * graph
filtergraph this filter belongs to
Definition: avfilter.h:355
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition: avfilter.h:125
const char * name
Pad name.
Definition: internal.h:60
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1080
static float lanczos_kernel(float x)
Definition: vf_lensfun.c:194
uint8_t
#define av_cold
Definition: attributes.h:82
const char * lens_model
Definition: vf_lensfun.c:77
AVOptions.
static uint32_t reverse(uint32_t num, int bits)
Definition: speedhq.c:565
#define f(width, name)
Definition: cbs_vp9.c:255
const char * model
Definition: vf_lensfun.c:77
static int query_formats(AVFilterContext *ctx)
Definition: vf_lensfun.c:186
Mode
Frame type (Table 1a in 3GPP TS 26.101)
Definition: amrnbdata.h:39
int nb_threads
Maximum number of threads used by filters in this graph.
Definition: avfilter.h:869
InterpolationType
Definition: vf_lensfun.c:50
const float * distortion_coords
Definition: vf_lensfun.c:66
external API header
#define av_log(a,...)
A filter pad used for either input or output.
Definition: internal.h:54
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:568
static int distortion_correction_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_lensfun.c:312
static av_cold int init(AVFilterContext *ctx)
Definition: vf_lensfun.c:130
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
lfModifier * modifier
Definition: vf_lensfun.c:91
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:116
const char * arg
Definition: jacosubdec.c:66
simple assert() macros that are a bit more flexible than ISO C assert().
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_lensfun.c:503
static float square(float x)
Definition: vf_lensfun.c:307
int target_geometry
Definition: vf_lensfun.c:82
lfModifier * modifier
Definition: vf_lensfun.c:61
static const AVOption lensfun_options[]
Definition: vf_lensfun.c:96
AVFilter ff_vf_lensfun
Definition: vf_lensfun.c:535
#define FFMIN(a, b)
Definition: common.h:96
int interpolation_type
Definition: vf_lensfun.c:84
static int config_props(AVFilterLink *inlink)
Definition: vf_lensfun.c:205
float focal_length
Definition: vf_lensfun.c:79
AVFILTER_DEFINE_CLASS(lensfun)
AVFormatContext * ctx
Definition: movenc.c:48
float aperture
Definition: vf_lensfun.c:80
float * distortion_coords
Definition: vf_lensfun.c:86
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:257
static int vignetting_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_lensfun.c:289
const char * make
Definition: vf_lensfun.c:77
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31))))#defineSET_CONV_FUNC_GROUP(ofmt, ifmt) staticvoidset_generic_function(AudioConvert *ac){}voidff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, intsample_rate, intapply_map){AudioConvert *ac;intin_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) returnNULL;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);returnNULL;}returnac;}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;}elseif(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;elseac->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);returnac;}intff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){intuse_generic=1;intlen=in->nb_samples;intp;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%dsamples-audio_convert:%sto%s(dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));returnff_convert_dither(ac-> in
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
lfCamera * camera
Definition: vf_lensfun.c:90
int index
Definition: gxfenc.c:89
#define FLAGS
Definition: vf_lensfun.c:95
#define LANCZOS_RESOLUTION
Definition: vf_lensfun.c:42
const char * name
Filter name.
Definition: avfilter.h:148
static const AVFilterPad lensfun_inputs[]
Definition: vf_lensfun.c:517
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
float * interpolation
Definition: vf_lensfun.c:87
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition: frame.c:611
#define flags(name, subs,...)
Definition: cbs_av1.c:596
AVFilterInternal * internal
An opaque struct for libavfilter internal use.
Definition: avfilter.h:378
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:240
Definition: drawutils.c:33
int
lfLens * lens
Definition: vf_lensfun.c:89
avfilter_execute_func * execute
Definition: internal.h:155
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:2029
A list of supported formats for one end of a filter link.
Definition: formats.h:64
Definition: drawutils.c:33
An instance of a filter.
Definition: avfilter.h:338
float focus_distance
Definition: vf_lensfun.c:81
FILE * out
Definition: movenc.c:54
#define av_freep(p)
#define M_PI
Definition: mathematics.h:52
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:170
#define av_malloc_array(a, b)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lensfun.c:441
internal API functions
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
mode
Use these values in ebur128_init (or'ed).
Definition: ebur128.h:83
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:654