2 * Copyright (c) 2012 Jeremy Tran
3 * Copyright (c) 2004 Tobias Diedrich
4 * Copyright (c) 2003 Donald A. Graft
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.
26 * Ported from MPlayer libmpcodecs/vf_kerndeint.c.
29 #include "libavutil/imgutils.h"
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/opt.h"
32 #include "libavutil/pixdesc.h"
40 int frame
; ///< frame count, starting from 0
41 int thresh
, map
, order
, sharp
, twoway
;
44 uint8_t *tmp_data
[4]; ///< temporary plane data buffer
45 int tmp_linesize
[4]; ///< temporary plane byte linesize
46 int tmp_bwidth
[4]; ///< temporary plane byte width
49 #define OFFSET(x) offsetof(KerndeintContext, x)
50 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
51 static const AVOption kerndeint_options
[] = {
52 { "thresh", "set the threshold", OFFSET(thresh
), AV_OPT_TYPE_INT
, {.i64
=10}, 0, 255, FLAGS
},
53 { "map", "set the map", OFFSET(map
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
54 { "order", "set the order", OFFSET(order
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
55 { "sharp", "enable sharpening", OFFSET(sharp
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
56 { "twoway", "enable twoway", OFFSET(twoway
), AV_OPT_TYPE_INT
, {.i64
=0}, 0, 1, FLAGS
},
60 AVFILTER_DEFINE_CLASS(kerndeint
);
62 static av_cold
void uninit(AVFilterContext
*ctx
)
64 KerndeintContext
*kerndeint
= ctx
->priv
;
66 av_free(kerndeint
->tmp_data
[0]);
69 static int query_formats(AVFilterContext
*ctx
)
71 static const enum PixelFormat pix_fmts
[] = {
74 AV_PIX_FMT_ARGB
, AV_PIX_FMT_0RGB
,
75 AV_PIX_FMT_ABGR
, AV_PIX_FMT_0BGR
,
76 AV_PIX_FMT_RGBA
, AV_PIX_FMT_RGB0
,
77 AV_PIX_FMT_BGRA
, AV_PIX_FMT_BGR0
,
81 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
86 static int config_props(AVFilterLink
*inlink
)
88 KerndeintContext
*kerndeint
= inlink
->dst
->priv
;
89 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
92 kerndeint
->is_packed_rgb
= av_pix_fmt_desc_get(inlink
->format
)->flags
& AV_PIX_FMT_FLAG_RGB
;
93 kerndeint
->vsub
= desc
->log2_chroma_h
;
95 ret
= av_image_alloc(kerndeint
->tmp_data
, kerndeint
->tmp_linesize
,
96 inlink
->w
, inlink
->h
, inlink
->format
, 16);
99 memset(kerndeint
->tmp_data
[0], 0, ret
);
101 if ((ret
= av_image_fill_linesizes(kerndeint
->tmp_bwidth
, inlink
->format
, inlink
->w
)) < 0)
107 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpic
)
109 KerndeintContext
*kerndeint
= inlink
->dst
->priv
;
110 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
112 const uint8_t *prvp
; ///< Previous field's pixel line number n
113 const uint8_t *prvpp
; ///< Previous field's pixel line number (n - 1)
114 const uint8_t *prvpn
; ///< Previous field's pixel line number (n + 1)
115 const uint8_t *prvppp
; ///< Previous field's pixel line number (n - 2)
116 const uint8_t *prvpnn
; ///< Previous field's pixel line number (n + 2)
117 const uint8_t *prvp4p
; ///< Previous field's pixel line number (n - 4)
118 const uint8_t *prvp4n
; ///< Previous field's pixel line number (n + 4)
120 const uint8_t *srcp
; ///< Current field's pixel line number n
121 const uint8_t *srcpp
; ///< Current field's pixel line number (n - 1)
122 const uint8_t *srcpn
; ///< Current field's pixel line number (n + 1)
123 const uint8_t *srcppp
; ///< Current field's pixel line number (n - 2)
124 const uint8_t *srcpnn
; ///< Current field's pixel line number (n + 2)
125 const uint8_t *srcp3p
; ///< Current field's pixel line number (n - 3)
126 const uint8_t *srcp3n
; ///< Current field's pixel line number (n + 3)
127 const uint8_t *srcp4p
; ///< Current field's pixel line number (n - 4)
128 const uint8_t *srcp4n
; ///< Current field's pixel line number (n + 4)
130 uint8_t *dstp
, *dstp_saved
;
131 const uint8_t *srcp_saved
;
133 int src_linesize
, psrc_linesize
, dst_linesize
, bwidth
;
134 int x
, y
, plane
, val
, hi
, lo
, g
, h
, n
= kerndeint
->frame
++;
137 const int thresh
= kerndeint
->thresh
;
138 const int order
= kerndeint
->order
;
139 const int map
= kerndeint
->map
;
140 const int sharp
= kerndeint
->sharp
;
141 const int twoway
= kerndeint
->twoway
;
143 const int is_packed_rgb
= kerndeint
->is_packed_rgb
;
145 outpic
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
147 av_frame_free(&inpic
);
148 return AVERROR(ENOMEM
);
150 av_frame_copy_props(outpic
, inpic
);
151 outpic
->interlaced_frame
= 0;
153 for (plane
= 0; plane
< 4 && inpic
->data
[plane
] && inpic
->linesize
[plane
]; plane
++) {
154 h
= plane
== 0 ? inlink
->h
: FF_CEIL_RSHIFT(inlink
->h
, kerndeint
->vsub
);
155 bwidth
= kerndeint
->tmp_bwidth
[plane
];
157 srcp_saved
= inpic
->data
[plane
];
158 src_linesize
= inpic
->linesize
[plane
];
159 psrc_linesize
= kerndeint
->tmp_linesize
[plane
];
160 dstp_saved
= outpic
->data
[plane
];
161 dst_linesize
= outpic
->linesize
[plane
];
162 srcp
= srcp_saved
+ (1 - order
) * src_linesize
;
163 dstp
= dstp_saved
+ (1 - order
) * dst_linesize
;
165 for (y
= 0; y
< h
; y
+= 2) {
166 memcpy(dstp
, srcp
, bwidth
);
167 srcp
+= 2 * src_linesize
;
168 dstp
+= 2 * dst_linesize
;
171 // Copy through the lines that will be missed below.
172 memcpy(dstp_saved
+ order
* dst_linesize
, srcp_saved
+ (1 - order
) * src_linesize
, bwidth
);
173 memcpy(dstp_saved
+ (2 + order
) * dst_linesize
, srcp_saved
+ (3 - order
) * src_linesize
, bwidth
);
174 memcpy(dstp_saved
+ (h
- 2 + order
) * dst_linesize
, srcp_saved
+ (h
- 1 - order
) * src_linesize
, bwidth
);
175 memcpy(dstp_saved
+ (h
- 4 + order
) * dst_linesize
, srcp_saved
+ (h
- 3 - order
) * src_linesize
, bwidth
);
177 /* For the other field choose adaptively between using the previous field
178 or the interpolant from the current field. */
179 prvp
= kerndeint
->tmp_data
[plane
] + 5 * psrc_linesize
- (1 - order
) * psrc_linesize
;
180 prvpp
= prvp
- psrc_linesize
;
181 prvppp
= prvp
- 2 * psrc_linesize
;
182 prvp4p
= prvp
- 4 * psrc_linesize
;
183 prvpn
= prvp
+ psrc_linesize
;
184 prvpnn
= prvp
+ 2 * psrc_linesize
;
185 prvp4n
= prvp
+ 4 * psrc_linesize
;
187 srcp
= srcp_saved
+ 5 * src_linesize
- (1 - order
) * src_linesize
;
188 srcpp
= srcp
- src_linesize
;
189 srcppp
= srcp
- 2 * src_linesize
;
190 srcp3p
= srcp
- 3 * src_linesize
;
191 srcp4p
= srcp
- 4 * src_linesize
;
193 srcpn
= srcp
+ src_linesize
;
194 srcpnn
= srcp
+ 2 * src_linesize
;
195 srcp3n
= srcp
+ 3 * src_linesize
;
196 srcp4n
= srcp
+ 4 * src_linesize
;
198 dstp
= dstp_saved
+ 5 * dst_linesize
- (1 - order
) * dst_linesize
;
200 for (y
= 5 - (1 - order
); y
<= h
- 5 - (1 - order
); y
+= 2) {
201 for (x
= 0; x
< bwidth
; x
++) {
202 if (thresh
== 0 || n
== 0 ||
203 (abs((int)prvp
[x
] - (int)srcp
[x
]) > thresh
) ||
204 (abs((int)prvpp
[x
] - (int)srcpp
[x
]) > thresh
) ||
205 (abs((int)prvpn
[x
] - (int)srcpn
[x
]) > thresh
)) {
210 AV_WB32(dstp
+ g
, 0xffffffff);
212 } else if (inlink
->format
== AV_PIX_FMT_YUYV422
) {
213 // y <- 235, u <- 128, y <- 235, v <- 128
214 AV_WB32(dstp
+ g
, 0xeb80eb80);
217 dstp
[x
] = plane
== 0 ? 235 : 128;
223 } else if (inlink
->format
== AV_PIX_FMT_YUYV422
) {
224 hi
= x
& 1 ? 240 : 235;
227 hi
= plane
== 0 ? 235 : 240;
233 valf
= + 0.526 * ((int)srcpp
[x
] + (int)srcpn
[x
])
234 + 0.170 * ((int)srcp
[x
] + (int)prvp
[x
])
235 - 0.116 * ((int)srcppp
[x
] + (int)srcpnn
[x
] + (int)prvppp
[x
] + (int)prvpnn
[x
])
236 - 0.026 * ((int)srcp3p
[x
] + (int)srcp3n
[x
])
237 + 0.031 * ((int)srcp4p
[x
] + (int)srcp4n
[x
] + (int)prvp4p
[x
] + (int)prvp4n
[x
]);
239 valf
= + 0.526 * ((int)srcpp
[x
] + (int)srcpn
[x
])
240 + 0.170 * ((int)prvp
[x
])
241 - 0.116 * ((int)prvppp
[x
] + (int)prvpnn
[x
])
242 - 0.026 * ((int)srcp3p
[x
] + (int)srcp3n
[x
])
243 + 0.031 * ((int)prvp4p
[x
] + (int)prvp4p
[x
]);
245 dstp
[x
] = av_clip(valf
, lo
, hi
);
248 val
= (8 * ((int)srcpp
[x
] + (int)srcpn
[x
]) + 2 * ((int)srcp
[x
] + (int)prvp
[x
])
249 - (int)(srcppp
[x
]) - (int)(srcpnn
[x
])
250 - (int)(prvppp
[x
]) - (int)(prvpnn
[x
])) >> 4;
252 val
= (8 * ((int)srcpp
[x
] + (int)srcpn
[x
]) + 2 * ((int)prvp
[x
])
253 - (int)(prvppp
[x
]) - (int)(prvpnn
[x
])) >> 4;
255 dstp
[x
] = av_clip(val
, lo
, hi
);
262 prvp
+= 2 * psrc_linesize
;
263 prvpp
+= 2 * psrc_linesize
;
264 prvppp
+= 2 * psrc_linesize
;
265 prvpn
+= 2 * psrc_linesize
;
266 prvpnn
+= 2 * psrc_linesize
;
267 prvp4p
+= 2 * psrc_linesize
;
268 prvp4n
+= 2 * psrc_linesize
;
269 srcp
+= 2 * src_linesize
;
270 srcpp
+= 2 * src_linesize
;
271 srcppp
+= 2 * src_linesize
;
272 srcp3p
+= 2 * src_linesize
;
273 srcp4p
+= 2 * src_linesize
;
274 srcpn
+= 2 * src_linesize
;
275 srcpnn
+= 2 * src_linesize
;
276 srcp3n
+= 2 * src_linesize
;
277 srcp4n
+= 2 * src_linesize
;
278 dstp
+= 2 * dst_linesize
;
281 srcp
= inpic
->data
[plane
];
282 dstp
= kerndeint
->tmp_data
[plane
];
283 av_image_copy_plane(dstp
, psrc_linesize
, srcp
, src_linesize
, bwidth
, h
);
286 av_frame_free(&inpic
);
287 return ff_filter_frame(outlink
, outpic
);
290 static const AVFilterPad kerndeint_inputs
[] = {
293 .type
= AVMEDIA_TYPE_VIDEO
,
294 .filter_frame
= filter_frame
,
295 .config_props
= config_props
,
300 static const AVFilterPad kerndeint_outputs
[] = {
303 .type
= AVMEDIA_TYPE_VIDEO
,
309 AVFilter ff_vf_kerndeint
= {
311 .description
= NULL_IF_CONFIG_SMALL("Apply kernel deinterlacing to the input."),
312 .priv_size
= sizeof(KerndeintContext
),
313 .priv_class
= &kerndeint_class
,
315 .query_formats
= query_formats
,
316 .inputs
= kerndeint_inputs
,
317 .outputs
= kerndeint_outputs
,