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