2 * Copyright (c) 2002 Jindrich Makovicka <makovick@gmail.com>
3 * Copyright (c) 2011 Stefano Sabatini
4 * Copyright (c) 2013 Jean Delvare <khali@linux-fr.org>
6 * This file is part of FFmpeg.
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.
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.
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.
25 * A very simple tv station logo remover
26 * Originally imported from MPlayer libmpcodecs/vf_delogo.c,
27 * the algorithm was later improved.
30 #include "libavutil/common.h"
31 #include "libavutil/imgutils.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/pixdesc.h"
40 * Apply a simple delogo algorithm to the image in src and put the
43 * The algorithm is only applied to the region specified by the logo
46 * @param w width of the input image
47 * @param h height of the input image
48 * @param logo_x x coordinate of the top left corner of the logo region
49 * @param logo_y y coordinate of the top left corner of the logo region
50 * @param logo_w width of the logo
51 * @param logo_h height of the logo
52 * @param band the size of the band around the processed area
53 * @param show show a rectangle around the processed area, useful for
55 * @param direct if non-zero perform in-place processing
57 static void apply_delogo(uint8_t *dst
, int dst_linesize
,
58 uint8_t *src
, int src_linesize
,
59 int w
, int h
, AVRational sar
,
60 int logo_x
, int logo_y
, int logo_w
, int logo_h
,
61 unsigned int band
, int show
, int direct
)
64 uint64_t interp
, weightl
, weightr
, weightt
, weightb
;
67 uint8_t *topleft
, *botleft
, *topright
;
68 unsigned int left_sample
, right_sample
;
69 int xclipl
, xclipr
, yclipt
, yclipb
;
70 int logo_x1
, logo_x2
, logo_y1
, logo_y2
;
72 xclipl
= FFMAX(-logo_x
, 0);
73 xclipr
= FFMAX(logo_x
+logo_w
-w
, 0);
74 yclipt
= FFMAX(-logo_y
, 0);
75 yclipb
= FFMAX(logo_y
+logo_h
-h
, 0);
77 logo_x1
= logo_x
+ xclipl
;
78 logo_x2
= logo_x
+ logo_w
- xclipr
;
79 logo_y1
= logo_y
+ yclipt
;
80 logo_y2
= logo_y
+ logo_h
- yclipb
;
82 topleft
= src
+logo_y1
* src_linesize
+logo_x1
;
83 topright
= src
+logo_y1
* src_linesize
+logo_x2
-1;
84 botleft
= src
+(logo_y2
-1) * src_linesize
+logo_x1
;
87 av_image_copy_plane(dst
, dst_linesize
, src
, src_linesize
, w
, h
);
89 dst
+= (logo_y1
+ 1) * dst_linesize
;
90 src
+= (logo_y1
+ 1) * src_linesize
;
92 for (y
= logo_y1
+1; y
< logo_y2
-1; y
++) {
93 left_sample
= topleft
[src_linesize
*(y
-logo_y1
)] +
94 topleft
[src_linesize
*(y
-logo_y1
-1)] +
95 topleft
[src_linesize
*(y
-logo_y1
+1)];
96 right_sample
= topright
[src_linesize
*(y
-logo_y1
)] +
97 topright
[src_linesize
*(y
-logo_y1
-1)] +
98 topright
[src_linesize
*(y
-logo_y1
+1)];
101 xdst
= dst
+logo_x1
+1,
102 xsrc
= src
+logo_x1
+1; x
< logo_x2
-1; x
++, xdst
++, xsrc
++) {
104 /* Weighted interpolation based on relative distances, taking SAR into account */
105 weightl
= (uint64_t) (logo_x2
-1-x
) * (y
-logo_y1
) * (logo_y2
-1-y
) * sar
.den
;
106 weightr
= (uint64_t)(x
-logo_x1
) * (y
-logo_y1
) * (logo_y2
-1-y
) * sar
.den
;
107 weightt
= (uint64_t)(x
-logo_x1
) * (logo_x2
-1-x
) * (logo_y2
-1-y
) * sar
.num
;
108 weightb
= (uint64_t)(x
-logo_x1
) * (logo_x2
-1-x
) * (y
-logo_y1
) * sar
.num
;
111 left_sample
* weightl
113 right_sample
* weightr
115 (topleft
[x
-logo_x1
] +
116 topleft
[x
-logo_x1
-1] +
117 topleft
[x
-logo_x1
+1]) * weightt
119 (botleft
[x
-logo_x1
] +
120 botleft
[x
-logo_x1
-1] +
121 botleft
[x
-logo_x1
+1]) * weightb
;
122 interp
/= (weightl
+ weightr
+ weightt
+ weightb
) * 3U;
124 if (y
>= logo_y
+band
&& y
< logo_y
+logo_h
-band
&&
125 x
>= logo_x
+band
&& x
< logo_x
+logo_w
-band
) {
131 dist
= FFMAX(dist
, logo_x
-x
+band
);
132 else if (x
>= logo_x
+logo_w
-band
)
133 dist
= FFMAX(dist
, x
-(logo_x
+logo_w
-1-band
));
136 dist
= FFMAX(dist
, logo_y
-y
+band
);
137 else if (y
>= logo_y
+logo_h
-band
)
138 dist
= FFMAX(dist
, y
-(logo_y
+logo_h
-1-band
));
140 *xdst
= (*xsrc
*dist
+ interp
*(band
-dist
))/band
;
141 if (show
&& (dist
== band
-1))
151 typedef struct DelogoContext
{
152 const AVClass
*class;
153 int x
, y
, w
, h
, band
, show
;
156 #define OFFSET(x) offsetof(DelogoContext, x)
157 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
159 static const AVOption delogo_options
[]= {
160 { "x", "set logo x position", OFFSET(x
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, FLAGS
},
161 { "y", "set logo y position", OFFSET(y
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, FLAGS
},
162 { "w", "set logo width", OFFSET(w
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, FLAGS
},
163 { "h", "set logo height", OFFSET(h
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, INT_MAX
, FLAGS
},
164 { "band", "set delogo area band size", OFFSET(band
), AV_OPT_TYPE_INT
, { .i64
= 4 }, 1, INT_MAX
, FLAGS
},
165 { "t", "set delogo area band size", OFFSET(band
), AV_OPT_TYPE_INT
, { .i64
= 4 }, 1, INT_MAX
, FLAGS
},
166 { "show", "show delogo area", OFFSET(show
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 1, FLAGS
},
170 AVFILTER_DEFINE_CLASS(delogo
);
172 static int query_formats(AVFilterContext
*ctx
)
174 static const enum AVPixelFormat pix_fmts
[] = {
175 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUV420P
,
176 AV_PIX_FMT_YUV411P
, AV_PIX_FMT_YUV410P
, AV_PIX_FMT_YUV440P
,
177 AV_PIX_FMT_YUVA420P
, AV_PIX_FMT_GRAY8
,
181 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
185 static av_cold
int init(AVFilterContext
*ctx
)
187 DelogoContext
*s
= ctx
->priv
;
189 #define CHECK_UNSET_OPT(opt) \
190 if (s->opt == -1) { \
191 av_log(s, AV_LOG_ERROR, "Option %s was not set.\n", #opt); \
192 return AVERROR(EINVAL); \
199 av_log(ctx
, AV_LOG_VERBOSE
, "x:%d y:%d, w:%d h:%d band:%d show:%d\n",
200 s
->x
, s
->y
, s
->w
, s
->h
, s
->band
, s
->show
);
210 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
212 DelogoContext
*s
= inlink
->dst
->priv
;
213 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
214 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
216 int hsub0
= desc
->log2_chroma_w
;
217 int vsub0
= desc
->log2_chroma_h
;
222 if (av_frame_is_writable(in
)) {
226 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
229 return AVERROR(ENOMEM
);
232 av_frame_copy_props(out
, in
);
235 sar
= in
->sample_aspect_ratio
;
236 /* Assume square pixels if SAR is unknown */
238 sar
.num
= sar
.den
= 1;
240 for (plane
= 0; plane
< 4 && in
->data
[plane
] && in
->linesize
[plane
]; plane
++) {
241 int hsub
= plane
== 1 || plane
== 2 ? hsub0
: 0;
242 int vsub
= plane
== 1 || plane
== 2 ? vsub0
: 0;
244 apply_delogo(out
->data
[plane
], out
->linesize
[plane
],
245 in
->data
[plane
], in
->linesize
[plane
],
246 FF_CEIL_RSHIFT(inlink
->w
, hsub
),
247 FF_CEIL_RSHIFT(inlink
->h
, vsub
),
248 sar
, s
->x
>>hsub
, s
->y
>>vsub
,
249 /* Up and left borders were rounded down, inject lost bits
250 * into width and height to avoid error accumulation */
251 FF_CEIL_RSHIFT(s
->w
+ (s
->x
& ((1<<hsub
)-1)), hsub
),
252 FF_CEIL_RSHIFT(s
->h
+ (s
->y
& ((1<<vsub
)-1)), vsub
),
253 s
->band
>>FFMIN(hsub
, vsub
),
260 return ff_filter_frame(outlink
, out
);
263 static const AVFilterPad avfilter_vf_delogo_inputs
[] = {
266 .type
= AVMEDIA_TYPE_VIDEO
,
267 .filter_frame
= filter_frame
,
272 static const AVFilterPad avfilter_vf_delogo_outputs
[] = {
275 .type
= AVMEDIA_TYPE_VIDEO
,
280 AVFilter ff_vf_delogo
= {
282 .description
= NULL_IF_CONFIG_SMALL("Remove logo from input video."),
283 .priv_size
= sizeof(DelogoContext
),
284 .priv_class
= &delogo_class
,
286 .query_formats
= query_formats
,
287 .inputs
= avfilter_vf_delogo_inputs
,
288 .outputs
= avfilter_vf_delogo_outputs
,
289 .flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,