2 * Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at>
3 * 2010 James Darnley <james.darnley@gmail.com>
5 * This file is part of Libav.
7 * Libav 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 2 of the License, or
10 * (at your option) any later version.
12 * Libav 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.
17 * You should have received a copy of the GNU General Public License along
18 * with Libav; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "libavutil/cpu.h"
23 #include "libavutil/common.h"
24 #include "libavutil/pixdesc.h"
34 #define PERM_RWP AV_PERM_WRITE | AV_PERM_PRESERVE | AV_PERM_REUSE
37 { int score = FFABS(cur[mrefs-1+(j)] - cur[prefs-1-(j)])\
38 + FFABS(cur[mrefs +(j)] - cur[prefs -(j)])\
39 + FFABS(cur[mrefs+1+(j)] - cur[prefs+1-(j)]);\
40 if (score < spatial_score) {\
41 spatial_score= score;\
42 spatial_pred= (cur[mrefs +(j)] + cur[prefs -(j)])>>1;\
45 for (x = 0; x < w; x++) { \
47 int d = (prev2[0] + next2[0])>>1; \
49 int temporal_diff0 = FFABS(prev2[0] - next2[0]); \
50 int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \
51 int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \
52 int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
53 int spatial_pred = (c+e) >> 1; \
54 int spatial_score = FFABS(cur[mrefs - 1] - cur[prefs - 1]) + FFABS(c-e) \
55 + FFABS(cur[mrefs + 1] - cur[prefs + 1]) - 1; \
57 CHECK(-1) CHECK(-2) }} }} \
58 CHECK( 1) CHECK( 2) }} }} \
61 int b = (prev2[2 * mrefs] + next2[2 * mrefs])>>1; \
62 int f = (prev2[2 * prefs] + next2[2 * prefs])>>1; \
63 int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
64 int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \
66 diff = FFMAX3(diff, min, -max); \
69 if (spatial_pred > d + diff) \
70 spatial_pred = d + diff; \
71 else if (spatial_pred < d - diff) \
72 spatial_pred = d - diff; \
74 dst[0] = spatial_pred; \
84 static void filter_line_c(uint8_t *dst
,
85 uint8_t *prev
, uint8_t *cur
, uint8_t *next
,
86 int w
, int prefs
, int mrefs
, int parity
, int mode
)
89 uint8_t *prev2
= parity
? prev
: cur
;
90 uint8_t *next2
= parity
? cur
: next
;
95 static void filter_line_c_16bit(uint16_t *dst
,
96 uint16_t *prev
, uint16_t *cur
, uint16_t *next
,
97 int w
, int prefs
, int mrefs
, int parity
,
101 uint16_t *prev2
= parity
? prev
: cur
;
102 uint16_t *next2
= parity
? cur
: next
;
109 static void filter(AVFilterContext
*ctx
, AVFilterBufferRef
*dstpic
,
112 YADIFContext
*yadif
= ctx
->priv
;
115 for (i
= 0; i
< yadif
->csp
->nb_components
; i
++) {
116 int w
= dstpic
->video
->w
;
117 int h
= dstpic
->video
->h
;
118 int refs
= yadif
->cur
->linesize
[i
];
119 int df
= (yadif
->csp
->comp
[i
].depth_minus1
+ 8) / 8;
121 if (i
== 1 || i
== 2) {
122 /* Why is this not part of the per-plane description thing? */
123 w
>>= yadif
->csp
->log2_chroma_w
;
124 h
>>= yadif
->csp
->log2_chroma_h
;
127 for (y
= 0; y
< h
; y
++) {
128 if ((y
^ parity
) & 1) {
129 uint8_t *prev
= &yadif
->prev
->data
[i
][y
* refs
];
130 uint8_t *cur
= &yadif
->cur
->data
[i
][y
* refs
];
131 uint8_t *next
= &yadif
->next
->data
[i
][y
* refs
];
132 uint8_t *dst
= &dstpic
->data
[i
][y
* dstpic
->linesize
[i
]];
133 int mode
= y
== 1 || y
+ 2 == h
? 2 : yadif
->mode
;
134 yadif
->filter_line(dst
, prev
, cur
, next
, w
,
135 y
+ 1 < h
? refs
: -refs
,
139 memcpy(&dstpic
->data
[i
][y
* dstpic
->linesize
[i
]],
140 &yadif
->cur
->data
[i
][y
* refs
], w
* df
);
148 static AVFilterBufferRef
*get_video_buffer(AVFilterLink
*link
, int perms
,
151 AVFilterBufferRef
*picref
;
152 int width
= FFALIGN(w
, 32);
153 int height
= FFALIGN(h
+ 2, 32);
156 picref
= ff_default_get_video_buffer(link
, perms
, width
, height
);
158 picref
->video
->w
= w
;
159 picref
->video
->h
= h
;
161 for (i
= 0; i
< 3; i
++)
162 picref
->data
[i
] += picref
->linesize
[i
];
167 static int return_frame(AVFilterContext
*ctx
, int is_second
)
169 YADIFContext
*yadif
= ctx
->priv
;
170 AVFilterLink
*link
= ctx
->outputs
[0];
173 if (yadif
->parity
== -1) {
174 tff
= yadif
->cur
->video
->interlaced
?
175 yadif
->cur
->video
->top_field_first
: 1;
177 tff
= yadif
->parity
^ 1;
181 yadif
->out
= ff_get_video_buffer(link
, PERM_RWP
, link
->w
, link
->h
);
183 return AVERROR(ENOMEM
);
185 avfilter_copy_buffer_ref_props(yadif
->out
, yadif
->cur
);
186 yadif
->out
->video
->interlaced
= 0;
190 yadif
->csp
= av_pix_fmt_desc_get(link
->format
);
191 if (yadif
->csp
->comp
[0].depth_minus1
/ 8 == 1)
192 yadif
->filter_line
= filter_line_c_16bit
;
194 filter(ctx
, yadif
->out
, tff
^ !is_second
, tff
);
197 int64_t cur_pts
= yadif
->cur
->pts
;
198 int64_t next_pts
= yadif
->next
->pts
;
200 if (next_pts
!= AV_NOPTS_VALUE
&& cur_pts
!= AV_NOPTS_VALUE
) {
201 yadif
->out
->pts
= cur_pts
+ next_pts
;
203 yadif
->out
->pts
= AV_NOPTS_VALUE
;
206 ret
= ff_filter_frame(ctx
->outputs
[0], yadif
->out
);
208 yadif
->frame_pending
= (yadif
->mode
&1) && !is_second
;
212 static int filter_frame(AVFilterLink
*link
, AVFilterBufferRef
*picref
)
214 AVFilterContext
*ctx
= link
->dst
;
215 YADIFContext
*yadif
= ctx
->priv
;
217 if (yadif
->frame_pending
)
218 return_frame(ctx
, 1);
221 avfilter_unref_buffer(yadif
->prev
);
222 yadif
->prev
= yadif
->cur
;
223 yadif
->cur
= yadif
->next
;
224 yadif
->next
= picref
;
229 if (yadif
->auto_enable
&& !yadif
->cur
->video
->interlaced
) {
230 yadif
->out
= avfilter_ref_buffer(yadif
->cur
, AV_PERM_READ
);
232 return AVERROR(ENOMEM
);
234 avfilter_unref_bufferp(&yadif
->prev
);
235 if (yadif
->out
->pts
!= AV_NOPTS_VALUE
)
236 yadif
->out
->pts
*= 2;
237 return ff_filter_frame(ctx
->outputs
[0], yadif
->out
);
241 !(yadif
->prev
= avfilter_ref_buffer(yadif
->cur
, AV_PERM_READ
)))
242 return AVERROR(ENOMEM
);
244 yadif
->out
= ff_get_video_buffer(ctx
->outputs
[0], PERM_RWP
,
247 return AVERROR(ENOMEM
);
249 avfilter_copy_buffer_ref_props(yadif
->out
, yadif
->cur
);
250 yadif
->out
->video
->interlaced
= 0;
252 if (yadif
->out
->pts
!= AV_NOPTS_VALUE
)
253 yadif
->out
->pts
*= 2;
255 return return_frame(ctx
, 0);
258 static int request_frame(AVFilterLink
*link
)
260 AVFilterContext
*ctx
= link
->src
;
261 YADIFContext
*yadif
= ctx
->priv
;
263 if (yadif
->frame_pending
) {
264 return_frame(ctx
, 1);
274 ret
= ff_request_frame(link
->src
->inputs
[0]);
276 if (ret
== AVERROR_EOF
&& yadif
->next
) {
277 AVFilterBufferRef
*next
=
278 avfilter_ref_buffer(yadif
->next
, AV_PERM_READ
);
281 return AVERROR(ENOMEM
);
283 next
->pts
= yadif
->next
->pts
* 2 - yadif
->cur
->pts
;
285 filter_frame(link
->src
->inputs
[0], next
);
287 } else if (ret
< 0) {
290 } while (!yadif
->cur
);
295 static int poll_frame(AVFilterLink
*link
)
297 YADIFContext
*yadif
= link
->src
->priv
;
300 if (yadif
->frame_pending
)
303 val
= ff_poll_frame(link
->src
->inputs
[0]);
307 //FIXME change API to not requre this red tape
308 if (val
== 1 && !yadif
->next
) {
309 if ((ret
= ff_request_frame(link
->src
->inputs
[0])) < 0)
311 val
= ff_poll_frame(link
->src
->inputs
[0]);
315 assert(yadif
->next
|| !val
);
317 if (yadif
->auto_enable
&& yadif
->next
&& !yadif
->next
->video
->interlaced
)
320 return val
* ((yadif
->mode
&1)+1);
323 static av_cold
void uninit(AVFilterContext
*ctx
)
325 YADIFContext
*yadif
= ctx
->priv
;
327 if (yadif
->prev
) avfilter_unref_bufferp(&yadif
->prev
);
328 if (yadif
->cur
) avfilter_unref_bufferp(&yadif
->cur
);
329 if (yadif
->next
) avfilter_unref_bufferp(&yadif
->next
);
332 static int query_formats(AVFilterContext
*ctx
)
334 static const enum AVPixelFormat pix_fmts
[] = {
344 AV_NE( AV_PIX_FMT_GRAY16BE
, AV_PIX_FMT_GRAY16LE
),
347 AV_NE( AV_PIX_FMT_YUV420P10BE
, AV_PIX_FMT_YUV420P10LE
),
348 AV_NE( AV_PIX_FMT_YUV422P10BE
, AV_PIX_FMT_YUV422P10LE
),
349 AV_NE( AV_PIX_FMT_YUV444P10BE
, AV_PIX_FMT_YUV444P10LE
),
350 AV_NE( AV_PIX_FMT_YUV420P16BE
, AV_PIX_FMT_YUV420P16LE
),
351 AV_NE( AV_PIX_FMT_YUV422P16BE
, AV_PIX_FMT_YUV422P16LE
),
352 AV_NE( AV_PIX_FMT_YUV444P16BE
, AV_PIX_FMT_YUV444P16LE
),
357 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
362 static av_cold
int init(AVFilterContext
*ctx
, const char *args
)
364 YADIFContext
*yadif
= ctx
->priv
;
368 yadif
->auto_enable
= 0;
372 sscanf(args
, "%d:%d:%d",
373 &yadif
->mode
, &yadif
->parity
, &yadif
->auto_enable
);
375 yadif
->filter_line
= filter_line_c
;
378 ff_yadif_init_x86(yadif
);
380 av_log(ctx
, AV_LOG_VERBOSE
, "mode:%d parity:%d auto_enable:%d\n",
381 yadif
->mode
, yadif
->parity
, yadif
->auto_enable
);
386 static int config_props(AVFilterLink
*link
)
388 link
->time_base
.num
= link
->src
->inputs
[0]->time_base
.num
;
389 link
->time_base
.den
= link
->src
->inputs
[0]->time_base
.den
* 2;
390 link
->w
= link
->src
->inputs
[0]->w
;
391 link
->h
= link
->src
->inputs
[0]->h
;
396 static const AVFilterPad avfilter_vf_yadif_inputs
[] = {
399 .type
= AVMEDIA_TYPE_VIDEO
,
400 .get_video_buffer
= get_video_buffer
,
401 .filter_frame
= filter_frame
,
406 static const AVFilterPad avfilter_vf_yadif_outputs
[] = {
409 .type
= AVMEDIA_TYPE_VIDEO
,
410 .poll_frame
= poll_frame
,
411 .request_frame
= request_frame
,
412 .config_props
= config_props
,
417 AVFilter avfilter_vf_yadif
= {
419 .description
= NULL_IF_CONFIG_SMALL("Deinterlace the input image"),
421 .priv_size
= sizeof(YADIFContext
),
424 .query_formats
= query_formats
,
426 .inputs
= avfilter_vf_yadif_inputs
,
428 .outputs
= avfilter_vf_yadif_outputs
,