FFmpeg
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/mem.h"
32 #include "libavutil/opt.h"
33 #include "avfilter.h"
34 #include "filters.h"
35 #include "internal.h"
36 #include "video.h"
37 
38 #include <lensfun.h>
39 
40 #define LANCZOS_RESOLUTION 256
41 
42 enum Mode {
43  VIGNETTING = 0x1,
46 };
47 
52 };
53 
54 typedef struct VignettingThreadData {
55  int width, height;
56  uint8_t *data_in;
59  lfModifier *modifier;
61 
63  int width, height;
64  const float *distortion_coords;
65  const uint8_t *data_in;
66  uint8_t *data_out;
68  const float *interpolation;
69  int mode;
72 
73 typedef struct LensfunContext {
74  const AVClass *class;
75  const char *make, *model, *lens_model, *db_path;
76  int mode;
77  float focal_length;
78  float aperture;
80  float scale;
82  int reverse;
84 
86  float *interpolation;
87 
88  lfLens *lens;
89  lfCamera *camera;
90  lfModifier *modifier;
92 
93 #define OFFSET(x) offsetof(LensfunContext, x)
94 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
95 static const AVOption lensfun_options[] = {
96  { "make", "set camera maker", OFFSET(make), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
97  { "model", "set camera model", OFFSET(model), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
98  { "lens_model", "set lens model", OFFSET(lens_model), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
99  { "db_path", "set path to database", OFFSET(db_path), 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, .unit = "mode" },
101  { "vignetting", "fix lens vignetting", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING}, 0, 0, FLAGS, .unit = "mode" },
102  { "geometry", "correct geometry distortion", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRY_DISTORTION}, 0, 0, FLAGS, .unit = "mode" },
103  { "subpixel", "fix chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=SUBPIXEL_DISTORTION}, 0, 0, FLAGS, .unit = "mode" },
104  { "vig_geo", "fix lens vignetting and correct geometry distortion", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | GEOMETRY_DISTORTION}, 0, 0, FLAGS, .unit = "mode" },
105  { "vig_subpixel", "fix lens vignetting and chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, .unit = "mode" },
106  { "distortion", "correct geometry distortion and chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, .unit = "mode" },
107  { "all", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, .unit = "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  { "scale", "scale factor applied after corrections (0.0 means automatic scaling)", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, DBL_MAX, FLAGS },
112  { "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, .unit = "lens_geometry" },
113  { "rectilinear", "rectilinear lens (default)", 0, AV_OPT_TYPE_CONST, {.i64=LF_RECTILINEAR}, 0, 0, FLAGS, .unit = "lens_geometry" },
114  { "fisheye", "fisheye lens", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE}, 0, 0, FLAGS, .unit = "lens_geometry" },
115  { "panoramic", "panoramic (cylindrical)", 0, AV_OPT_TYPE_CONST, {.i64=LF_PANORAMIC}, 0, 0, FLAGS, .unit = "lens_geometry" },
116  { "equirectangular", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=LF_EQUIRECTANGULAR}, 0, 0, FLAGS, .unit = "lens_geometry" },
117  { "fisheye_orthographic", "orthographic fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_ORTHOGRAPHIC}, 0, 0, FLAGS, .unit = "lens_geometry" },
118  { "fisheye_stereographic", "stereographic fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_STEREOGRAPHIC}, 0, 0, FLAGS, .unit = "lens_geometry" },
119  { "fisheye_equisolid", "equisolid fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_EQUISOLID}, 0, 0, FLAGS, .unit = "lens_geometry" },
120  { "fisheye_thoby", "fisheye as measured by thoby", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_THOBY}, 0, 0, FLAGS, .unit = "lens_geometry" },
121  { "reverse", "Does reverse correction (regular image to lens distorted)", OFFSET(reverse), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
122  { "interpolation", "Type of interpolation", OFFSET(interpolation_type), AV_OPT_TYPE_INT, {.i64=LINEAR}, 0, LANCZOS, FLAGS, .unit = "interpolation" },
123  { "nearest", NULL, 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, .unit = "interpolation" },
124  { "linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, .unit = "interpolation" },
125  { "lanczos", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, .unit = "interpolation" },
126  { NULL }
127 };
128 
129 AVFILTER_DEFINE_CLASS(lensfun);
130 
132 {
133  LensfunContext *lensfun = ctx->priv;
134  lfDatabase *db;
135  const lfCamera **cameras;
136  const lfLens **lenses;
137 
138  db = lf_db_create();
139  if ((lensfun->db_path ? lf_db_load_path(db, lensfun->db_path) : lf_db_load(db)) != LF_NO_ERROR) {
140  lf_db_destroy(db);
141  av_log(ctx, AV_LOG_FATAL, "Failed to load lensfun database from %s path\n",
142  lensfun->db_path ? lensfun->db_path : "default");
143  return AVERROR_INVALIDDATA;
144  }
145 
146  if (!lensfun->make || !lensfun->model) {
147  const lfCamera *const *cameras = lf_db_get_cameras(db);
148 
149  av_log(ctx, AV_LOG_FATAL, "Option \"make\" or option \"model\" not specified\n");
150  av_log(ctx, AV_LOG_INFO, "Available values for \"make\" and \"model\":\n");
151  for (int i = 0; cameras && cameras[i]; i++)
152  av_log(ctx, AV_LOG_INFO, "\t%s\t%s\n", cameras[i]->Maker, cameras[i]->Model);
153  lf_db_destroy(db);
154  return AVERROR(EINVAL);
155  } else if (!lensfun->lens_model) {
156  const lfLens *const *lenses = lf_db_get_lenses(db);
157 
158  av_log(ctx, AV_LOG_FATAL, "Option \"lens_model\" not specified\n");
159  av_log(ctx, AV_LOG_INFO, "Available values for \"lens_model\":\n");
160  for (int i = 0; lenses && lenses[i]; i++)
161  av_log(ctx, AV_LOG_INFO, "\t%s\t(make %s)\n", lenses[i]->Model, lenses[i]->Maker);
162  lf_db_destroy(db);
163  return AVERROR(EINVAL);
164  }
165 
166  lensfun->lens = lf_lens_create();
167  lensfun->camera = lf_camera_create();
168 
169  cameras = lf_db_find_cameras(db, lensfun->make, lensfun->model);
170  if (cameras && *cameras) {
171  lf_camera_copy(lensfun->camera, *cameras);
172  av_log(ctx, AV_LOG_INFO, "Using camera %s\n", lensfun->camera->Model);
173  } else {
174  lf_free(cameras);
175  lf_db_destroy(db);
176  av_log(ctx, AV_LOG_FATAL, "Failed to find camera in lensfun database\n");
177  return AVERROR_INVALIDDATA;
178  }
179  lf_free(cameras);
180 
181  lenses = lf_db_find_lenses(db, lensfun->camera, NULL, lensfun->lens_model, 0);
182  if (lenses && *lenses) {
183  lf_lens_copy(lensfun->lens, *lenses);
184  av_log(ctx, AV_LOG_INFO, "Using lens %s\n", lensfun->lens->Model);
185  } else {
186  lf_free(lenses);
187  lf_db_destroy(db);
188  av_log(ctx, AV_LOG_FATAL, "Failed to find lens in lensfun database\n");
189  return AVERROR_INVALIDDATA;
190  }
191  lf_free(lenses);
192 
193  lf_db_destroy(db);
194  return 0;
195 }
196 
197 static float lanczos_kernel(float x)
198 {
199  if (x == 0.0f) {
200  return 1.0f;
201  } else if (x > -2.0f && x < 2.0f) {
202  return (2.0f * sin(M_PI * x) * sin(M_PI / 2.0f * x)) / (M_PI * M_PI * x * x);
203  } else {
204  return 0.0f;
205  }
206 }
207 
209 {
210  AVFilterContext *ctx = inlink->dst;
211  LensfunContext *lensfun = ctx->priv;
212  int index;
213  float a;
214 
215  if (!lensfun->modifier) {
216  if (lensfun->camera && lensfun->lens) {
217  lensfun->modifier = lf_modifier_create(lensfun->lens,
218  lensfun->focal_length,
219  lensfun->camera->CropFactor,
220  inlink->w,
221  inlink->h, LF_PF_U8, lensfun->reverse);
222  if (lensfun->mode & VIGNETTING)
223  lf_modifier_enable_vignetting_correction(lensfun->modifier, lensfun->aperture, lensfun->focus_distance);
224  if (lensfun->mode & GEOMETRY_DISTORTION) {
225  lf_modifier_enable_distortion_correction(lensfun->modifier);
226  lf_modifier_enable_projection_transform(lensfun->modifier, lensfun->target_geometry);
227  lf_modifier_enable_scaling(lensfun->modifier, lensfun->scale);
228  }
229  if (lensfun->mode & SUBPIXEL_DISTORTION)
230  lf_modifier_enable_tca_correction(lensfun->modifier);
231  } else {
232  // lensfun->camera and lensfun->lens should have been initialized
233  return AVERROR_BUG;
234  }
235  }
236 
237  if (!lensfun->distortion_coords) {
238  if (lensfun->mode & SUBPIXEL_DISTORTION) {
239  lensfun->distortion_coords = av_malloc_array(inlink->w * inlink->h, sizeof(float) * 2 * 3);
240  if (!lensfun->distortion_coords)
241  return AVERROR(ENOMEM);
242  if (lensfun->mode & GEOMETRY_DISTORTION) {
243  // apply both geometry and subpixel distortion
244  lf_modifier_apply_subpixel_geometry_distortion(lensfun->modifier,
245  0, 0,
246  inlink->w, inlink->h,
247  lensfun->distortion_coords);
248  } else {
249  // apply only subpixel distortion
250  lf_modifier_apply_subpixel_distortion(lensfun->modifier,
251  0, 0,
252  inlink->w, inlink->h,
253  lensfun->distortion_coords);
254  }
255  } else if (lensfun->mode & GEOMETRY_DISTORTION) {
256  lensfun->distortion_coords = av_malloc_array(inlink->w * inlink->h, sizeof(float) * 2);
257  if (!lensfun->distortion_coords)
258  return AVERROR(ENOMEM);
259  // apply only geometry distortion
260  lf_modifier_apply_geometry_distortion(lensfun->modifier,
261  0, 0,
262  inlink->w, inlink->h,
263  lensfun->distortion_coords);
264  }
265  }
266 
267  if (!lensfun->interpolation)
268  if (lensfun->interpolation_type == LANCZOS) {
269  lensfun->interpolation = av_malloc_array(LANCZOS_RESOLUTION, sizeof(float) * 4);
270  if (!lensfun->interpolation)
271  return AVERROR(ENOMEM);
272  for (index = 0; index < 4 * LANCZOS_RESOLUTION; ++index) {
273  if (index == 0) {
274  lensfun->interpolation[index] = 1.0f;
275  } else {
276  a = sqrtf((float)index / LANCZOS_RESOLUTION);
277  lensfun->interpolation[index] = lanczos_kernel(a);
278  }
279  }
280  }
281 
282  return 0;
283 }
284 
285 static int vignetting_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
286 {
288  const int slice_start = thread_data->height * jobnr / nb_jobs;
289  const int slice_end = thread_data->height * (jobnr + 1) / nb_jobs;
290 
291  lf_modifier_apply_color_modification(thread_data->modifier,
292  thread_data->data_in + slice_start * thread_data->linesize_in,
293  0,
294  slice_start,
295  thread_data->width,
297  thread_data->pixel_composition,
298  thread_data->linesize_in);
299 
300  return 0;
301 }
302 
303 static float square(float x)
304 {
305  return x * x;
306 }
307 
308 static int distortion_correction_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
309 {
311  const int slice_start = thread_data->height * jobnr / nb_jobs;
312  const int slice_end = thread_data->height * (jobnr + 1) / nb_jobs;
313 
314  int x, y, i, j, rgb_index;
315  float interpolated, new_x, new_y, d, norm;
316  int new_x_int, new_y_int;
317  for (y = slice_start; y < slice_end; ++y)
318  for (x = 0; x < thread_data->width; ++x)
319  for (rgb_index = 0; rgb_index < 3; ++rgb_index) {
320  if (thread_data->mode & SUBPIXEL_DISTORTION) {
321  // subpixel (and possibly geometry) distortion correction was applied, correct distortion
322  switch(thread_data->interpolation_type) {
323  case NEAREST:
324  new_x_int = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2] + 0.5f;
325  new_y_int = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1] + 0.5f;
326  if (new_x_int < 0 || new_x_int >= thread_data->width || new_y_int < 0 || new_y_int >= thread_data->height) {
327  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
328  } else {
329  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];
330  }
331  break;
332  case LINEAR:
333  interpolated = 0.0f;
334  new_x = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2];
335  new_x_int = new_x;
336  new_y = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1];
337  new_y_int = new_y;
338  if (new_x_int < 0 || new_x_int + 1 >= thread_data->width || new_y_int < 0 || new_y_int + 1 >= thread_data->height) {
339  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
340  } else {
341  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] =
342  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)
343  + 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)
344  + 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)
345  + 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);
346  }
347  break;
348  case LANCZOS:
349  interpolated = 0.0f;
350  norm = 0.0f;
351  new_x = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2];
352  new_x_int = new_x;
353  new_y = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1];
354  new_y_int = new_y;
355  for (j = 0; j < 4; ++j)
356  for (i = 0; i < 4; ++i) {
357  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)
358  continue;
359  d = square(new_x - (new_x_int + i - 2)) * square(new_y - (new_y_int + j - 2));
360  if (d >= 4.0f)
361  continue;
362  d = thread_data->interpolation[(int)(d * LANCZOS_RESOLUTION)];
363  norm += d;
364  interpolated += thread_data->data_in[(new_x_int + i - 2) * 3 + rgb_index + (new_y_int + j - 2) * thread_data->linesize_in] * d;
365  }
366  if (norm == 0.0f) {
367  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
368  } else {
369  interpolated /= norm;
370  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = interpolated < 0.0f ? 0.0f : interpolated > 255.0f ? 255.0f : interpolated;
371  }
372  break;
373  }
374  } else if (thread_data->mode & GEOMETRY_DISTORTION) {
375  // geometry distortion correction was applied, correct distortion
376  switch(thread_data->interpolation_type) {
377  case NEAREST:
378  new_x_int = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2] + 0.5f;
379  new_y_int = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2 + 1] + 0.5f;
380  if (new_x_int < 0 || new_x_int >= thread_data->width || new_y_int < 0 || new_y_int >= thread_data->height) {
381  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
382  } else {
383  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];
384  }
385  break;
386  case LINEAR:
387  interpolated = 0.0f;
388  new_x = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2];
389  new_x_int = new_x;
390  new_y = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2 + 1];
391  new_y_int = new_y;
392  if (new_x_int < 0 || new_x_int + 1 >= thread_data->width || new_y_int < 0 || new_y_int + 1 >= thread_data->height) {
393  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
394  } else {
395  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] =
396  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)
397  + 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)
398  + 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)
399  + 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);
400  }
401  break;
402  case LANCZOS:
403  interpolated = 0.0f;
404  norm = 0.0f;
405  new_x = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2];
406  new_x_int = new_x;
407  new_y = thread_data->distortion_coords[x * 2 + 1 + y * thread_data->width * 2];
408  new_y_int = new_y;
409  for (j = 0; j < 4; ++j)
410  for (i = 0; i < 4; ++i) {
411  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)
412  continue;
413  d = square(new_x - (new_x_int + i - 2)) * square(new_y - (new_y_int + j - 2));
414  if (d >= 4.0f)
415  continue;
416  d = thread_data->interpolation[(int)(d * LANCZOS_RESOLUTION)];
417  norm += d;
418  interpolated += thread_data->data_in[(new_x_int + i - 2) * 3 + rgb_index + (new_y_int + j - 2) * thread_data->linesize_in] * d;
419  }
420  if (norm == 0.0f) {
421  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0;
422  } else {
423  interpolated /= norm;
424  thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = interpolated < 0.0f ? 0.0f : interpolated > 255.0f ? 255.0f : interpolated;
425  }
426  break;
427  }
428  } else {
429  // no distortion correction was applied
430  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];
431  }
432  }
433 
434  return 0;
435 }
436 
438 {
439  AVFilterContext *ctx = inlink->dst;
440  LensfunContext *lensfun = ctx->priv;
441  AVFilterLink *outlink = ctx->outputs[0];
442  AVFrame *out;
443  VignettingThreadData vignetting_thread_data;
444  DistortionCorrectionThreadData distortion_correction_thread_data;
445  int ret;
446 
447  if (lensfun->mode & VIGNETTING) {
449  if (ret < 0) {
450  av_frame_free(&in);
451  return ret;
452  }
453 
454  vignetting_thread_data = (VignettingThreadData) {
455  .width = inlink->w,
456  .height = inlink->h,
457  .data_in = in->data[0],
458  .linesize_in = in->linesize[0],
459  .pixel_composition = LF_CR_3(RED, GREEN, BLUE),
460  .modifier = lensfun->modifier
461  };
462 
464  &vignetting_thread_data, NULL,
465  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
466  }
467 
468  if (lensfun->mode & (GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION)) {
469  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
470  if (!out) {
471  av_frame_free(&in);
472  return AVERROR(ENOMEM);
473  }
475 
476  distortion_correction_thread_data = (DistortionCorrectionThreadData) {
477  .width = inlink->w,
478  .height = inlink->h,
479  .distortion_coords = lensfun->distortion_coords,
480  .data_in = in->data[0],
481  .data_out = out->data[0],
482  .linesize_in = in->linesize[0],
483  .linesize_out = out->linesize[0],
484  .interpolation = lensfun->interpolation,
485  .mode = lensfun->mode,
486  .interpolation_type = lensfun->interpolation_type
487  };
488 
490  &distortion_correction_thread_data, NULL,
491  FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
492 
493  av_frame_free(&in);
494  return ff_filter_frame(outlink, out);
495  } else {
496  return ff_filter_frame(outlink, in);
497  }
498 }
499 
501 {
502  LensfunContext *lensfun = ctx->priv;
503 
504  if (lensfun->camera)
505  lf_camera_destroy(lensfun->camera);
506  if (lensfun->lens)
507  lf_lens_destroy(lensfun->lens);
508  if (lensfun->modifier)
509  lf_modifier_destroy(lensfun->modifier);
510  av_freep(&lensfun->distortion_coords);
511  av_freep(&lensfun->interpolation);
512 }
513 
514 static const AVFilterPad lensfun_inputs[] = {
515  {
516  .name = "default",
517  .type = AVMEDIA_TYPE_VIDEO,
518  .config_props = config_props,
519  .filter_frame = filter_frame,
520  },
521 };
522 
524  .name = "lensfun",
525  .description = NULL_IF_CONFIG_SMALL("Apply correction to an image based on info derived from the lensfun database."),
526  .priv_size = sizeof(LensfunContext),
527  .init = init,
528  .uninit = uninit,
532  .priv_class = &lensfun_class,
534 };
LensfunContext::focal_length
float focal_length
Definition: vf_lensfun.c:77
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:112
distortion_correction_filter_slice
static int distortion_correction_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_lensfun.c:308
AVERROR
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
opt.h
LINEAR
@ LINEAR
Definition: vf_lensfun.c:50
out
FILE * out
Definition: movenc.c:55
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1015
lanczos_kernel
static float lanczos_kernel(float x)
Definition: vf_lensfun.c:197
LensfunContext
Definition: vf_lensfun.c:73
inlink
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
Definition: filter_design.txt:212
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:160
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:375
LensfunContext::model
const char * model
Definition: vf_lensfun.c:75
AVOption
AVOption.
Definition: opt.h:346
DistortionCorrectionThreadData
Definition: vf_lensfun.c:62
float.h
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
LensfunContext::reverse
int reverse
Definition: vf_lensfun.c:82
LensfunContext::camera
lfCamera * camera
Definition: vf_lensfun.c:89
DistortionCorrectionThreadData::data_out
uint8_t * data_out
Definition: vf_lensfun.c:66
video.h
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:396
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_lensfun.c:500
VignettingThreadData::data_in
uint8_t * data_in
Definition: vf_lensfun.c:56
LensfunContext::interpolation
float * interpolation
Definition: vf_lensfun.c:86
OFFSET
#define OFFSET(x)
Definition: vf_lensfun.c:93
DistortionCorrectionThreadData::height
int height
Definition: vf_lensfun.c:63
BLUE
#define BLUE
Definition: vf_huesaturation.c:41
DistortionCorrectionThreadData::distortion_coords
const float * distortion_coords
Definition: vf_lensfun.c:64
lensfun_inputs
static const AVFilterPad lensfun_inputs[]
Definition: vf_lensfun.c:514
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:33
VignettingThreadData::pixel_composition
int pixel_composition
Definition: vf_lensfun.c:58
av_cold
#define av_cold
Definition: attributes.h:90
ff_video_default_filterpad
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition: video.c:37
thread_data
Definition: vf_lut.c:339
Mode
Mode
Frame type (Table 1a in 3GPP TS 26.101)
Definition: amrnbdata.h:39
VignettingThreadData::modifier
lfModifier * modifier
Definition: vf_lensfun.c:59
square
static float square(float x)
Definition: vf_lensfun.c:303
slice_end
static int slice_end(AVCodecContext *avctx, AVFrame *pict)
Handle slice ends.
Definition: mpeg12dec.c:1730
VignettingThreadData::width
int width
Definition: vf_lensfun.c:55
filters.h
DistortionCorrectionThreadData::mode
int mode
Definition: vf_lensfun.c:69
ctx
AVFormatContext * ctx
Definition: movenc.c:49
LensfunContext::db_path
const char * db_path
Definition: vf_lensfun.c:75
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
ff_inlink_make_frame_writable
int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe)
Make sure a frame is writable.
Definition: avfilter.c:1489
VignettingThreadData::linesize_in
int linesize_in
Definition: vf_lensfun.c:57
arg
const char * arg
Definition: jacosubdec.c:67
LensfunContext::focus_distance
float focus_distance
Definition: vf_lensfun.c:79
DistortionCorrectionThreadData::linesize_out
int linesize_out
Definition: vf_lensfun.c:67
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
DistortionCorrectionThreadData::linesize_in
int linesize_in
Definition: vf_lensfun.c:67
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:709
SUBPIXEL_DISTORTION
@ SUBPIXEL_DISTORTION
Definition: vf_lensfun.c:45
lensfun_options
static const AVOption lensfun_options[]
Definition: vf_lensfun.c:95
sqrtf
static __device__ float sqrtf(float a)
Definition: cuda_runtime.h:184
vignetting_filter_slice
static int vignetting_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: vf_lensfun.c:285
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
Definition: vf_lensfun.c:437
index
int index
Definition: gxfenc.c:90
LensfunContext::distortion_coords
float * distortion_coords
Definition: vf_lensfun.c:85
VignettingThreadData::height
int height
Definition: vf_lensfun.c:55
DistortionCorrectionThreadData::interpolation
const float * interpolation
Definition: vf_lensfun.c:68
f
f
Definition: af_crystalizer.c:121
LensfunContext::interpolation_type
int interpolation_type
Definition: vf_lensfun.c:83
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:75
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
LensfunContext::target_geometry
int target_geometry
Definition: vf_lensfun.c:81
LANCZOS
@ LANCZOS
Definition: vf_lensfun.c:51
LANCZOS_RESOLUTION
#define LANCZOS_RESOLUTION
Definition: vf_lensfun.c:40
FLAGS
#define FLAGS
Definition: vf_lensfun.c:94
NEAREST
@ NEAREST
Definition: vf_lensfun.c:49
a
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
Definition: undefined.txt:41
M_PI
#define M_PI
Definition: mathematics.h:67
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
internal.h
config_props
static int config_props(AVFilterLink *inlink)
Definition: vf_lensfun.c:208
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
#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:147
AV_OPT_TYPE_FLOAT
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:238
FILTER_SINGLE_PIXFMT
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition: internal.h:172
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
LensfunContext::aperture
float aperture
Definition: vf_lensfun.c:78
LensfunContext::make
const char * make
Definition: vf_lensfun.c:75
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:31
ff_filter_get_nb_threads
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:827
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
DistortionCorrectionThreadData::data_in
const uint8_t * data_in
Definition: vf_lensfun.c:65
AVFilter
Filter definition.
Definition: avfilter.h:166
ret
ret
Definition: filter_design.txt:187
AV_LOG_FATAL
#define AV_LOG_FATAL
Something went wrong and recovery is not possible.
Definition: log.h:174
LensfunContext::mode
int mode
Definition: vf_lensfun.c:76
InterpolationType
InterpolationType
Definition: vf_lensfun.c:48
LensfunContext::lens_model
const char * lens_model
Definition: vf_lensfun.c:75
GEOMETRY_DISTORTION
@ GEOMETRY_DISTORTION
Definition: vf_lensfun.c:44
DistortionCorrectionThreadData::interpolation_type
int interpolation_type
Definition: vf_lensfun.c:70
mode
mode
Definition: ebur128.h:83
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
avfilter.h
LensfunContext::scale
float scale
Definition: vf_lensfun.c:80
VignettingThreadData
Definition: vf_lensfun.c:54
LensfunContext::modifier
lfModifier * modifier
Definition: vf_lensfun.c:90
slice_start
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)
Definition: dec.c:688
RED
#define RED
Definition: vf_huesaturation.c:37
GREEN
#define GREEN
Definition: vf_huesaturation.c:39
AVFilterContext
An instance of a filter.
Definition: avfilter.h:407
AVFILTER_FLAG_SLICE_THREADS
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
VIGNETTING
@ VIGNETTING
Definition: vf_lensfun.c:43
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(lensfun)
DistortionCorrectionThreadData::width
int width
Definition: vf_lensfun.c:63
scale
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition: intra.c:291
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:251
Model
Definition: mss12.h:40
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
d
d
Definition: ffmpeg_filter.c:424
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:420
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
ff_filter_execute
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition: internal.h:134
int
int
Definition: ffmpeg_filter.c:424
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244
LensfunContext::lens
lfLens * lens
Definition: vf_lensfun.c:88
init
static av_cold int init(AVFilterContext *ctx)
Definition: vf_lensfun.c:131
ff_vf_lensfun
const AVFilter ff_vf_lensfun
Definition: vf_lensfun.c:523