Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2002 Jindrich Makovicka <makovick@gmail.com> | ||
3 | * Copyright (c) 2011 Stefano Sabatini | ||
4 | * Copyright (c) 2013, 2015 Jean Delvare <jdelvare@suse.com> | ||
5 | * | ||
6 | * This file is part of FFmpeg. | ||
7 | * | ||
8 | * FFmpeg is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * FFmpeg is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with FFmpeg; if not, write to the Free Software Foundation, Inc., | ||
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | */ | ||
22 | |||
23 | /** | ||
24 | * @file | ||
25 | * A very simple tv station logo remover | ||
26 | * Originally imported from MPlayer libmpcodecs/vf_delogo.c, | ||
27 | * the algorithm was later improved. | ||
28 | */ | ||
29 | |||
30 | #include "libavutil/common.h" | ||
31 | #include "libavutil/imgutils.h" | ||
32 | #include "libavutil/opt.h" | ||
33 | #include "libavutil/pixdesc.h" | ||
34 | #include "libavutil/eval.h" | ||
35 | #include "avfilter.h" | ||
36 | #include "filters.h" | ||
37 | #include "video.h" | ||
38 | static const char * const var_names[] = { | ||
39 | "x", | ||
40 | "y", | ||
41 | "w", | ||
42 | "h", | ||
43 | "n", ///< number of frame | ||
44 | "t", ///< timestamp expressed in seconds | ||
45 | NULL | ||
46 | }; | ||
47 | |||
48 | enum var_name { | ||
49 | VAR_X, | ||
50 | VAR_Y, | ||
51 | VAR_W, | ||
52 | VAR_H, | ||
53 | VAR_N, | ||
54 | VAR_T, | ||
55 | VAR_VARS_NB | ||
56 | }; | ||
57 | |||
58 | 8 | static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx) | |
59 | { | ||
60 | int ret; | ||
61 | 8 | AVExpr *old = NULL; | |
62 | |||
63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (*pexpr) |
64 | ✗ | old = *pexpr; | |
65 | 8 | ret = av_expr_parse(pexpr, expr, var_names, NULL, NULL, NULL, NULL, 0, log_ctx); | |
66 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (ret < 0) { |
67 | ✗ | av_log(log_ctx, AV_LOG_ERROR, | |
68 | "Error when parsing the expression '%s' for %s\n", | ||
69 | expr, option); | ||
70 | ✗ | *pexpr = old; | |
71 | ✗ | return ret; | |
72 | } | ||
73 | |||
74 | 8 | av_expr_free(old); | |
75 | 8 | return 0; | |
76 | } | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Apply a simple delogo algorithm to the image in src and put the | ||
81 | * result in dst. | ||
82 | * | ||
83 | * The algorithm is only applied to the region specified by the logo | ||
84 | * parameters. | ||
85 | * | ||
86 | * @param w width of the input image | ||
87 | * @param h height of the input image | ||
88 | * @param logo_x x coordinate of the top left corner of the logo region | ||
89 | * @param logo_y y coordinate of the top left corner of the logo region | ||
90 | * @param logo_w width of the logo | ||
91 | * @param logo_h height of the logo | ||
92 | * @param band the size of the band around the processed area | ||
93 | * @param show show a rectangle around the processed area, useful for | ||
94 | * parameters tweaking | ||
95 | * @param direct if non-zero perform in-place processing | ||
96 | */ | ||
97 | 327 | static void apply_delogo(uint8_t *dst, int dst_linesize, | |
98 | uint8_t *src, int src_linesize, | ||
99 | int w, int h, AVRational sar, | ||
100 | int logo_x, int logo_y, int logo_w, int logo_h, | ||
101 | unsigned int band, int show, int direct) | ||
102 | { | ||
103 | int x, y; | ||
104 | uint64_t interp, weightl, weightr, weightt, weightb, weight; | ||
105 | uint8_t *xdst, *xsrc; | ||
106 | |||
107 | uint8_t *topleft, *botleft, *topright; | ||
108 | unsigned int left_sample, right_sample; | ||
109 | int xclipl, xclipr, yclipt, yclipb; | ||
110 | int logo_x1, logo_x2, logo_y1, logo_y2; | ||
111 | |||
112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 327 times.
|
327 | xclipl = FFMAX(-logo_x, 0); |
113 | 327 | xclipr = FFMAX(logo_x+logo_w-w, 0); | |
114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 327 times.
|
327 | yclipt = FFMAX(-logo_y, 0); |
115 | 327 | yclipb = FFMAX(logo_y+logo_h-h, 0); | |
116 | |||
117 | 327 | logo_x1 = logo_x + xclipl; | |
118 | 327 | logo_x2 = logo_x + logo_w - xclipr - 1; | |
119 | 327 | logo_y1 = logo_y + yclipt; | |
120 | 327 | logo_y2 = logo_y + logo_h - yclipb - 1; | |
121 | |||
122 | 327 | topleft = src+logo_y1 * src_linesize+logo_x1; | |
123 | 327 | topright = src+logo_y1 * src_linesize+logo_x2; | |
124 | 327 | botleft = src+logo_y2 * src_linesize+logo_x1; | |
125 | |||
126 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 207 times.
|
327 | if (!direct) |
127 | 120 | av_image_copy_plane(dst, dst_linesize, src, src_linesize, w, h); | |
128 | |||
129 | 327 | dst += (logo_y1 + 1) * dst_linesize; | |
130 | 327 | src += (logo_y1 + 1) * src_linesize; | |
131 | |||
132 |
2/2✓ Branch 0 taken 3270 times.
✓ Branch 1 taken 327 times.
|
3597 | for (y = logo_y1+1; y < logo_y2; y++) { |
133 | 3270 | left_sample = topleft[src_linesize*(y-logo_y1)] + | |
134 | 3270 | topleft[src_linesize*(y-logo_y1-1)] + | |
135 | 3270 | topleft[src_linesize*(y-logo_y1+1)]; | |
136 | 3270 | right_sample = topright[src_linesize*(y-logo_y1)] + | |
137 | 3270 | topright[src_linesize*(y-logo_y1-1)] + | |
138 | 3270 | topright[src_linesize*(y-logo_y1+1)]; | |
139 | |||
140 | 3270 | for (x = logo_x1+1, | |
141 | 3270 | xdst = dst+logo_x1+1, | |
142 |
2/2✓ Branch 0 taken 65182 times.
✓ Branch 1 taken 3270 times.
|
68452 | xsrc = src+logo_x1+1; x < logo_x2; x++, xdst++, xsrc++) { |
143 | |||
144 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 65182 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
65182 | if (show && (y == logo_y1+1 || y == logo_y2-1 || |
145 | ✗ | x == logo_x1+1 || x == logo_x2-1)) { | |
146 | ✗ | *xdst = 0; | |
147 | ✗ | continue; | |
148 | } | ||
149 | |||
150 | /* Weighted interpolation based on relative distances, taking SAR into account */ | ||
151 | 65182 | weightl = (uint64_t) (logo_x2-x) * (y-logo_y1) * (logo_y2-y) * sar.den; | |
152 | 65182 | weightr = (uint64_t)(x-logo_x1) * (y-logo_y1) * (logo_y2-y) * sar.den; | |
153 | 65182 | weightt = (uint64_t)(x-logo_x1) * (logo_x2-x) * (logo_y2-y) * sar.num; | |
154 | 65182 | weightb = (uint64_t)(x-logo_x1) * (logo_x2-x) * (y-logo_y1) * sar.num; | |
155 | |||
156 | 65182 | interp = | |
157 | 65182 | left_sample * weightl | |
158 | 65182 | + | |
159 | 65182 | right_sample * weightr | |
160 | + | ||
161 | 65182 | (topleft[x-logo_x1] + | |
162 | 65182 | topleft[x-logo_x1-1] + | |
163 | 65182 | topleft[x-logo_x1+1]) * weightt | |
164 | 65182 | + | |
165 | 65182 | (botleft[x-logo_x1] + | |
166 | 65182 | botleft[x-logo_x1-1] + | |
167 | 65182 | botleft[x-logo_x1+1]) * weightb; | |
168 | 65182 | weight = (weightl + weightr + weightt + weightb) * 3U; | |
169 | 65182 | interp = (interp + (weight >> 1)) / weight; | |
170 | |||
171 |
2/4✓ Branch 0 taken 65182 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65182 times.
✗ Branch 3 not taken.
|
65182 | if (y >= logo_y+band && y < logo_y+logo_h-band && |
172 |
2/4✓ Branch 0 taken 65182 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65182 times.
✗ Branch 3 not taken.
|
65182 | x >= logo_x+band && x < logo_x+logo_w-band) { |
173 | 65182 | *xdst = interp; | |
174 | } else { | ||
175 | ✗ | unsigned dist = 0; | |
176 | |||
177 | ✗ | if (x < logo_x+band) | |
178 | ✗ | dist = FFMAX(dist, logo_x-x+band); | |
179 | ✗ | else if (x >= logo_x+logo_w-band) | |
180 | ✗ | dist = FFMAX(dist, x-(logo_x+logo_w-1-band)); | |
181 | |||
182 | ✗ | if (y < logo_y+band) | |
183 | ✗ | dist = FFMAX(dist, logo_y-y+band); | |
184 | ✗ | else if (y >= logo_y+logo_h-band) | |
185 | ✗ | dist = FFMAX(dist, y-(logo_y+logo_h-1-band)); | |
186 | |||
187 | ✗ | *xdst = (*xsrc*dist + interp*(band-dist))/band; | |
188 | } | ||
189 | } | ||
190 | |||
191 | 3270 | dst += dst_linesize; | |
192 | 3270 | src += src_linesize; | |
193 | } | ||
194 | 327 | } | |
195 | |||
196 | typedef struct DelogoContext { | ||
197 | const AVClass *class; | ||
198 | int x, y, w, h, band, show; | ||
199 | char *x_expr, *y_expr, *w_expr, *h_expr; | ||
200 | AVExpr *x_pexpr, *y_pexpr, *w_pexpr, *h_pexpr; | ||
201 | double var_values[VAR_VARS_NB]; | ||
202 | } DelogoContext; | ||
203 | |||
204 | #define OFFSET(x) offsetof(DelogoContext, x) | ||
205 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM | ||
206 | |||
207 | static const AVOption delogo_options[]= { | ||
208 | { "x", "set logo x position", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str = "-1" }, 0, 0, FLAGS }, | ||
209 | { "y", "set logo y position", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str = "-1" }, 0, 0, FLAGS }, | ||
210 | { "w", "set logo width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "-1" }, 0, 0, FLAGS }, | ||
211 | { "h", "set logo height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "-1" }, 0, 0, FLAGS }, | ||
212 | { "show", "show delogo area", OFFSET(show), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, | ||
213 | { NULL } | ||
214 | }; | ||
215 | |||
216 | AVFILTER_DEFINE_CLASS(delogo); | ||
217 | 2 | static av_cold void uninit(AVFilterContext *ctx) | |
218 | { | ||
219 | 2 | DelogoContext *s = ctx->priv; | |
220 | |||
221 | 2 | av_expr_free(s->x_pexpr); s->x_pexpr = NULL; | |
222 | 2 | av_expr_free(s->y_pexpr); s->y_pexpr = NULL; | |
223 | 2 | av_expr_free(s->w_pexpr); s->w_pexpr = NULL; | |
224 | 2 | av_expr_free(s->h_pexpr); s->h_pexpr = NULL; | |
225 | 2 | } | |
226 | |||
227 | static const enum AVPixelFormat pix_fmts[] = { | ||
228 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, | ||
229 | AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, | ||
230 | AV_PIX_FMT_YUVA420P, AV_PIX_FMT_GRAY8, | ||
231 | AV_PIX_FMT_NONE | ||
232 | }; | ||
233 | |||
234 | 2 | static av_cold int init(AVFilterContext *ctx) | |
235 | { | ||
236 | 2 | DelogoContext *s = ctx->priv; | |
237 | 2 | int ret = 0; | |
238 | |||
239 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
4 | if ((ret = set_expr(&s->x_pexpr, s->x_expr, "x", ctx)) < 0 || |
240 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | (ret = set_expr(&s->y_pexpr, s->y_expr, "y", ctx)) < 0 || |
241 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
4 | (ret = set_expr(&s->w_pexpr, s->w_expr, "w", ctx)) < 0 || |
242 | 2 | (ret = set_expr(&s->h_pexpr, s->h_expr, "h", ctx)) < 0 ) | |
243 | ✗ | return ret; | |
244 | |||
245 | 2 | s->x = av_expr_eval(s->x_pexpr, s->var_values, s); | |
246 | 2 | s->y = av_expr_eval(s->y_pexpr, s->var_values, s); | |
247 | 2 | s->w = av_expr_eval(s->w_pexpr, s->var_values, s); | |
248 | 2 | s->h = av_expr_eval(s->h_pexpr, s->var_values, s); | |
249 | |||
250 | #define CHECK_UNSET_OPT(opt) \ | ||
251 | if (s->opt == -1) { \ | ||
252 | av_log(s, AV_LOG_ERROR, "Option %s was not set.\n", #opt); \ | ||
253 | return AVERROR(EINVAL); \ | ||
254 | } | ||
255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CHECK_UNSET_OPT(x); |
256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CHECK_UNSET_OPT(y); |
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CHECK_UNSET_OPT(w); |
258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | CHECK_UNSET_OPT(h); |
259 | |||
260 | 2 | s->band = 1; | |
261 | |||
262 | 2 | av_log(ctx, AV_LOG_VERBOSE, "x:%d y:%d, w:%d h:%d band:%d show:%d\n", | |
263 | s->x, s->y, s->w, s->h, s->band, s->show); | ||
264 | |||
265 | 2 | s->w += s->band*2; | |
266 | 2 | s->h += s->band*2; | |
267 | 2 | s->x -= s->band; | |
268 | 2 | s->y -= s->band; | |
269 | |||
270 | 2 | return 0; | |
271 | } | ||
272 | |||
273 | 110 | static int config_input(AVFilterLink *inlink) | |
274 | { | ||
275 | 110 | DelogoContext *s = inlink->dst->priv; | |
276 | |||
277 | /* Check whether the logo area fits in the frame */ | ||
278 |
2/4✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
|
110 | if (s->x + (s->band - 1) < 0 || s->x + s->w - (s->band*2 - 2) > inlink->w || |
279 |
2/4✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 110 times.
|
110 | s->y + (s->band - 1) < 0 || s->y + s->h - (s->band*2 - 2) > inlink->h) { |
280 | ✗ | av_log(s, AV_LOG_ERROR, "Logo area is outside of the frame.\n"); | |
281 | ✗ | return AVERROR(EINVAL); | |
282 | } | ||
283 | |||
284 | 110 | return 0; | |
285 | } | ||
286 | |||
287 | 109 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |
288 | { | ||
289 | 109 | FilterLink *inl = ff_filter_link(inlink); | |
290 | 109 | DelogoContext *s = inlink->dst->priv; | |
291 | 109 | AVFilterLink *outlink = inlink->dst->outputs[0]; | |
292 | 109 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); | |
293 | AVFrame *out; | ||
294 | 109 | int hsub0 = desc->log2_chroma_w; | |
295 | 109 | int vsub0 = desc->log2_chroma_h; | |
296 | 109 | int direct = 0; | |
297 | int plane; | ||
298 | AVRational sar; | ||
299 | int ret; | ||
300 | |||
301 | 109 | s->var_values[VAR_N] = inl->frame_count_out; | |
302 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
109 | s->var_values[VAR_T] = TS2T(in->pts, inlink->time_base); |
303 | 109 | s->x = av_expr_eval(s->x_pexpr, s->var_values, s); | |
304 | 109 | s->y = av_expr_eval(s->y_pexpr, s->var_values, s); | |
305 | 109 | s->w = av_expr_eval(s->w_pexpr, s->var_values, s); | |
306 | 109 | s->h = av_expr_eval(s->h_pexpr, s->var_values, s); | |
307 | |||
308 |
2/4✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 109 times.
✗ Branch 3 not taken.
|
109 | if (s->x + (s->band - 1) <= 0 || s->x + s->w - (s->band*2 - 2) > inlink->w || |
309 |
2/4✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 109 times.
|
109 | s->y + (s->band - 1) <= 0 || s->y + s->h - (s->band*2 - 2) > inlink->h) { |
310 | ✗ | av_log(s, AV_LOG_WARNING, "Logo area is outside of the frame," | |
311 | " auto set the area inside of the frame\n"); | ||
312 | } | ||
313 | |||
314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | if (s->x + (s->band - 1) <= 0) |
315 | ✗ | s->x = 1 + s->band; | |
316 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | if (s->y + (s->band - 1) <= 0) |
317 | ✗ | s->y = 1 + s->band; | |
318 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | if (s->x + s->w - (s->band*2 - 2) > inlink->w) |
319 | ✗ | s->w = inlink->w - s->x - (s->band*2 - 2); | |
320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | if (s->y + s->h - (s->band*2 - 2) > inlink->h) |
321 | ✗ | s->h = inlink->h - s->y - (s->band*2 - 2); | |
322 | |||
323 | 109 | ret = config_input(inlink); | |
324 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | if (ret < 0) { |
325 | ✗ | av_frame_free(&in); | |
326 | ✗ | return ret; | |
327 | } | ||
328 | |||
329 | 109 | s->w += s->band*2; | |
330 | 109 | s->h += s->band*2; | |
331 | 109 | s->x -= s->band; | |
332 | 109 | s->y -= s->band; | |
333 | |||
334 |
2/2✓ Branch 1 taken 69 times.
✓ Branch 2 taken 40 times.
|
109 | if (av_frame_is_writable(in)) { |
335 | 69 | direct = 1; | |
336 | 69 | out = in; | |
337 | } else { | ||
338 | 40 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); | |
339 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
|
40 | if (!out) { |
340 | ✗ | av_frame_free(&in); | |
341 | ✗ | return AVERROR(ENOMEM); | |
342 | } | ||
343 | |||
344 | 40 | av_frame_copy_props(out, in); | |
345 | } | ||
346 | |||
347 | 109 | sar = in->sample_aspect_ratio; | |
348 | /* Assume square pixels if SAR is unknown */ | ||
349 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
109 | if (!sar.num) |
350 | 109 | sar.num = sar.den = 1; | |
351 | |||
352 |
2/2✓ Branch 0 taken 327 times.
✓ Branch 1 taken 109 times.
|
436 | for (plane = 0; plane < desc->nb_components; plane++) { |
353 |
4/4✓ Branch 0 taken 218 times.
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 109 times.
|
327 | int hsub = plane == 1 || plane == 2 ? hsub0 : 0; |
354 |
4/4✓ Branch 0 taken 218 times.
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 109 times.
|
327 | int vsub = plane == 1 || plane == 2 ? vsub0 : 0; |
355 | |||
356 | 327 | apply_delogo(out->data[plane], out->linesize[plane], | |
357 | 327 | in ->data[plane], in ->linesize[plane], | |
358 | 327 | AV_CEIL_RSHIFT(inlink->w, hsub), | |
359 | 327 | AV_CEIL_RSHIFT(inlink->h, vsub), | |
360 | 327 | sar, s->x>>hsub, s->y>>vsub, | |
361 | /* Up and left borders were rounded down, inject lost bits | ||
362 | * into width and height to avoid error accumulation */ | ||
363 | 327 | AV_CEIL_RSHIFT(s->w + (s->x & ((1<<hsub)-1)), hsub), | |
364 | 327 | AV_CEIL_RSHIFT(s->h + (s->y & ((1<<vsub)-1)), vsub), | |
365 | 327 | s->band>>FFMIN(hsub, vsub), | |
366 | s->show, direct); | ||
367 | } | ||
368 | |||
369 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 69 times.
|
109 | if (!direct) |
370 | 40 | av_frame_free(&in); | |
371 | |||
372 | 109 | return ff_filter_frame(outlink, out); | |
373 | } | ||
374 | |||
375 | static const AVFilterPad avfilter_vf_delogo_inputs[] = { | ||
376 | { | ||
377 | .name = "default", | ||
378 | .type = AVMEDIA_TYPE_VIDEO, | ||
379 | .filter_frame = filter_frame, | ||
380 | .config_props = config_input, | ||
381 | }, | ||
382 | }; | ||
383 | |||
384 | const AVFilter ff_vf_delogo = { | ||
385 | .name = "delogo", | ||
386 | .description = NULL_IF_CONFIG_SMALL("Remove logo from input video."), | ||
387 | .priv_size = sizeof(DelogoContext), | ||
388 | .priv_class = &delogo_class, | ||
389 | .init = init, | ||
390 | .uninit = uninit, | ||
391 | FILTER_INPUTS(avfilter_vf_delogo_inputs), | ||
392 | FILTER_OUTPUTS(ff_video_default_filterpad), | ||
393 | FILTER_PIXFMTS_ARRAY(pix_fmts), | ||
394 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, | ||
395 | }; | ||
396 |