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