2 * Copyright (C) 2007 Richard Spindler (author of frei0r plugin from which this was derived)
3 * Copyright (C) 2014 Daniel Oberhoff
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg 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 GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * Lenscorrection filter, algorithm from the frei0r plugin with the same name
29 #include "libavutil/opt.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/pixdesc.h"
37 typedef struct LenscorrectionCtx
{
38 const AVClass
*av_class
;
43 double cx
, cy
, k1
, k2
;
44 int32_t *correction
[4];
47 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
48 static const AVOption lenscorrection_options
[] = {
49 { "cx", "set relative center x", offsetof(LenscorrectionCtx
, cx
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.5}, 0, 1, .flags
=FLAGS
},
50 { "cy", "set relative center y", offsetof(LenscorrectionCtx
, cy
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.5}, 0, 1, .flags
=FLAGS
},
51 { "k1", "set quadratic distortion factor", offsetof(LenscorrectionCtx
, k1
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.0}, -1, 1, .flags
=FLAGS
},
52 { "k2", "set double quadratic distortion factor", offsetof(LenscorrectionCtx
, k2
), AV_OPT_TYPE_DOUBLE
, {.dbl
=0.0}, -1, 1, .flags
=FLAGS
},
56 AVFILTER_DEFINE_CLASS(lenscorrection
);
58 typedef struct ThreadData
{
66 static int filter_slice(AVFilterContext
*ctx
, void *arg
, int job
, int nb_jobs
)
68 ThreadData
*td
= (ThreadData
*)arg
;
70 AVFrame
*out
= td
->out
;
72 const int w
= td
->w
, h
= td
->h
;
73 const int xcenter
= td
->xcenter
;
74 const int ycenter
= td
->ycenter
;
75 const int start
= (h
* job
) / nb_jobs
;
76 const int end
= (h
* (job
+1)) / nb_jobs
;
77 const int plane
= td
->plane
;
78 const int inlinesize
= in
->linesize
[plane
];
79 const int outlinesize
= out
->linesize
[plane
];
80 const uint8_t *indata
= in
->data
[plane
];
81 uint8_t *outrow
= out
->data
[plane
] + start
* outlinesize
;
83 for (i
= start
; i
< end
; i
++, outrow
+= outlinesize
) {
84 const int off_y
= i
- ycenter
;
85 uint8_t *out
= outrow
;
87 for (j
= 0; j
< w
; j
++) {
88 const int off_x
= j
- xcenter
;
89 const int64_t radius_mult
= td
->correction
[j
+ i
*w
];
90 const int x
= xcenter
+ ((radius_mult
* off_x
+ (1<<23))>>24);
91 const int y
= ycenter
+ ((radius_mult
* off_y
+ (1<<23))>>24);
92 const char isvalid
= x
> 0 && x
< w
- 1 && y
> 0 && y
< h
- 1;
93 *out
++ = isvalid
? indata
[y
* inlinesize
+ x
] : 0;
99 static int query_formats(AVFilterContext
*ctx
)
101 static const enum AVPixelFormat pix_fmts
[] = {
103 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUVJ444P
,
104 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUVJ420P
,
105 AV_PIX_FMT_YUVA444P
, AV_PIX_FMT_YUVA420P
,
110 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
114 static av_cold
void uninit(AVFilterContext
*ctx
)
116 LenscorrectionCtx
*rect
= ctx
->priv
;
119 for (i
= 0; i
< FF_ARRAY_ELEMS(rect
->correction
); i
++) {
120 av_freep(&rect
->correction
[i
]);
124 static int config_props(AVFilterLink
*outlink
)
126 AVFilterContext
*ctx
= outlink
->src
;
127 LenscorrectionCtx
*rect
= ctx
->priv
;
128 AVFilterLink
*inlink
= ctx
->inputs
[0];
129 const AVPixFmtDescriptor
*pixdesc
= av_pix_fmt_desc_get(inlink
->format
);
130 rect
->hsub
= pixdesc
->log2_chroma_w
;
131 rect
->vsub
= pixdesc
->log2_chroma_h
;
132 outlink
->w
= rect
->width
= inlink
->w
;
133 outlink
->h
= rect
->height
= inlink
->h
;
134 rect
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
138 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
140 AVFilterContext
*ctx
= inlink
->dst
;
141 AVFilterLink
*outlink
= ctx
->outputs
[0];
142 LenscorrectionCtx
*rect
= (LenscorrectionCtx
*)ctx
->priv
;
143 AVFrame
*out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
148 return AVERROR(ENOMEM
);
151 av_frame_copy_props(out
, in
);
153 for (plane
= 0; plane
< rect
->nb_planes
; ++plane
) {
154 int hsub
= plane
== 1 || plane
== 2 ? rect
->hsub
: 0;
155 int vsub
= plane
== 1 || plane
== 2 ? rect
->vsub
: 0;
156 int hdiv
= 1 << hsub
;
157 int vdiv
= 1 << vsub
;
158 int w
= rect
->width
/ hdiv
;
159 int h
= rect
->height
/ vdiv
;
160 int xcenter
= rect
->cx
* w
;
161 int ycenter
= rect
->cy
* h
;
162 int k1
= rect
->k1
* (1<<24);
163 int k2
= rect
->k2
* (1<<24);
173 if (!rect
->correction
[plane
]) {
175 const int64_t r2inv
= (4LL<<60) / (w
* w
+ h
* h
);
177 rect
->correction
[plane
] = av_malloc_array(w
, h
* sizeof(**rect
->correction
));
178 if (!rect
->correction
[plane
])
179 return AVERROR(ENOMEM
);
180 for (j
= 0; j
< h
; j
++) {
181 const int off_y
= j
- ycenter
;
182 const int off_y2
= off_y
* off_y
;
183 for (i
= 0; i
< w
; i
++) {
184 const int off_x
= i
- xcenter
;
185 const int64_t r2
= ((off_x
* off_x
+ off_y2
) * r2inv
+ (1LL<<31)) >> 32;
186 const int64_t r4
= (r2
* r2
+ (1<<27)) >> 28;
187 const int radius_mult
= (r2
* k1
+ r4
* k2
+ (1LL<<27) + (1LL<<52))>>28;
188 rect
->correction
[plane
][j
* w
+ i
] = radius_mult
;
193 td
.correction
= rect
->correction
[plane
];
194 ctx
->internal
->execute(ctx
, filter_slice
, &td
, NULL
, FFMIN(h
, ctx
->graph
->nb_threads
));
198 return ff_filter_frame(outlink
, out
);
201 static const AVFilterPad lenscorrection_inputs
[] = {
204 .type
= AVMEDIA_TYPE_VIDEO
,
205 .filter_frame
= filter_frame
,
210 static const AVFilterPad lenscorrection_outputs
[] = {
213 .type
= AVMEDIA_TYPE_VIDEO
,
214 .config_props
= config_props
,
219 AVFilter ff_vf_lenscorrection
= {
220 .name
= "lenscorrection",
221 .description
= NULL_IF_CONFIG_SMALL("Rectify the image by correcting for lens distortion."),
222 .priv_size
= sizeof(LenscorrectionCtx
),
223 .query_formats
= query_formats
,
224 .inputs
= lenscorrection_inputs
,
225 .outputs
= lenscorrection_outputs
,
226 .priv_class
= &lenscorrection_class
,
228 .flags
= AVFILTER_FLAG_SLICE_THREADS
,