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
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 * 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 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 Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/cpu.h"
23 #include "libavutil/common.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/pixdesc.h"
35 typedef struct ThreadData
{
46 { int score = FFABS(cur[mrefs - 1 + (j)] - cur[prefs - 1 - (j)])\
47 + FFABS(cur[mrefs +(j)] - cur[prefs -(j)])\
48 + FFABS(cur[mrefs + 1 + (j)] - cur[prefs + 1 - (j)]);\
49 if (score < spatial_score) {\
50 spatial_score= score;\
51 spatial_pred= (cur[mrefs +(j)] + cur[prefs -(j)])>>1;\
53 /* The is_not_edge argument here controls when the code will enter a branch
54 * which reads up to and including x-3 and x+3. */
56 #define FILTER(start, end, is_not_edge) \
57 for (x = start; x < end; x++) { \
59 int d = (prev2[0] + next2[0])>>1; \
61 int temporal_diff0 = FFABS(prev2[0] - next2[0]); \
62 int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \
63 int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \
64 int diff = FFMAX3(temporal_diff0 >> 1, temporal_diff1, temporal_diff2); \
65 int spatial_pred = (c+e) >> 1; \
68 int spatial_score = FFABS(cur[mrefs - 1] - cur[prefs - 1]) + FFABS(c-e) \
69 + FFABS(cur[mrefs + 1] - cur[prefs + 1]) - 1; \
70 CHECK(-1) CHECK(-2) }} }} \
71 CHECK( 1) CHECK( 2) }} }} \
75 int b = (prev2[2 * mrefs] + next2[2 * mrefs])>>1; \
76 int f = (prev2[2 * prefs] + next2[2 * prefs])>>1; \
77 int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
78 int min = FFMIN3(d - e, d - c, FFMAX(b - c, f - e)); \
80 diff = FFMAX3(diff, min, -max); \
83 if (spatial_pred > d + diff) \
84 spatial_pred = d + diff; \
85 else if (spatial_pred < d - diff) \
86 spatial_pred = d - diff; \
88 dst[0] = spatial_pred; \
98 static void filter_line_c(void *dst1
,
99 void *prev1
, void *cur1
, void *next1
,
100 int w
, int prefs
, int mrefs
, int parity
, int mode
)
103 uint8_t *prev
= prev1
;
105 uint8_t *next
= next1
;
107 uint8_t *prev2
= parity
? prev
: cur
;
108 uint8_t *next2
= parity
? cur
: next
;
110 /* The function is called with the pointers already pointing to data[3] and
111 * with 6 subtracted from the width. This allows the FILTER macro to be
112 * called so that it processes all the pixels normally. A constant value of
113 * true for is_not_edge lets the compiler ignore the if statement. */
117 static void filter_edges(void *dst1
, void *prev1
, void *cur1
, void *next1
,
118 int w
, int prefs
, int mrefs
, int parity
, int mode
)
121 uint8_t *prev
= prev1
;
123 uint8_t *next
= next1
;
125 uint8_t *prev2
= parity
? prev
: cur
;
126 uint8_t *next2
= parity
? cur
: next
;
128 const int edge
= MAX_ALIGN
- 1;
130 /* Only edge pixels need to be processed here. A constant value of false
131 * for is_not_edge should let the compiler ignore the whole branch. */
134 dst
= (uint8_t*)dst1
+ w
- edge
;
135 prev
= (uint8_t*)prev1
+ w
- edge
;
136 cur
= (uint8_t*)cur1
+ w
- edge
;
137 next
= (uint8_t*)next1
+ w
- edge
;
138 prev2
= (uint8_t*)(parity
? prev
: cur
);
139 next2
= (uint8_t*)(parity
? cur
: next
);
141 FILTER(w
- edge
, w
- 3, 1)
146 static void filter_line_c_16bit(void *dst1
,
147 void *prev1
, void *cur1
, void *next1
,
148 int w
, int prefs
, int mrefs
, int parity
,
151 uint16_t *dst
= dst1
;
152 uint16_t *prev
= prev1
;
153 uint16_t *cur
= cur1
;
154 uint16_t *next
= next1
;
156 uint16_t *prev2
= parity
? prev
: cur
;
157 uint16_t *next2
= parity
? cur
: next
;
164 static void filter_edges_16bit(void *dst1
, void *prev1
, void *cur1
, void *next1
,
165 int w
, int prefs
, int mrefs
, int parity
, int mode
)
167 uint16_t *dst
= dst1
;
168 uint16_t *prev
= prev1
;
169 uint16_t *cur
= cur1
;
170 uint16_t *next
= next1
;
172 uint16_t *prev2
= parity
? prev
: cur
;
173 uint16_t *next2
= parity
? cur
: next
;
175 const int edge
= MAX_ALIGN
/ 2 - 1;
182 dst
= (uint16_t*)dst1
+ w
- edge
;
183 prev
= (uint16_t*)prev1
+ w
- edge
;
184 cur
= (uint16_t*)cur1
+ w
- edge
;
185 next
= (uint16_t*)next1
+ w
- edge
;
186 prev2
= (uint16_t*)(parity
? prev
: cur
);
187 next2
= (uint16_t*)(parity
? cur
: next
);
189 FILTER(w
- edge
, w
- 3, 1)
193 static int filter_slice(AVFilterContext
*ctx
, void *arg
, int jobnr
, int nb_jobs
)
195 YADIFContext
*s
= ctx
->priv
;
196 ThreadData
*td
= arg
;
197 int refs
= s
->cur
->linesize
[td
->plane
];
198 int df
= (s
->csp
->comp
[td
->plane
].depth
+ 7) / 8;
200 int slice_h
= td
->h
/ nb_jobs
;
201 int slice_start
= jobnr
* slice_h
;
202 int slice_end
= (jobnr
== nb_jobs
- 1) ? td
->h
: (jobnr
+ 1) * slice_h
;
204 int edge
= 3 + MAX_ALIGN
/ df
- 1;
206 /* filtering reads 3 pixels to the left/right; to avoid invalid reads,
207 * we need to call the c variant which avoids this for border pixels
209 for (y
= slice_start
; y
< slice_end
; y
++) {
210 if ((y
^ td
->parity
) & 1) {
211 uint8_t *prev
= &s
->prev
->data
[td
->plane
][y
* refs
];
212 uint8_t *cur
= &s
->cur
->data
[td
->plane
][y
* refs
];
213 uint8_t *next
= &s
->next
->data
[td
->plane
][y
* refs
];
214 uint8_t *dst
= &td
->frame
->data
[td
->plane
][y
* td
->frame
->linesize
[td
->plane
]];
215 int mode
= y
== 1 || y
+ 2 == td
->h
? 2 : s
->mode
;
216 s
->filter_line(dst
+ pix_3
, prev
+ pix_3
, cur
+ pix_3
,
217 next
+ pix_3
, td
->w
- edge
,
218 y
+ 1 < td
->h
? refs
: -refs
,
220 td
->parity
^ td
->tff
, mode
);
221 s
->filter_edges(dst
, prev
, cur
, next
, td
->w
,
222 y
+ 1 < td
->h
? refs
: -refs
,
224 td
->parity
^ td
->tff
, mode
);
226 memcpy(&td
->frame
->data
[td
->plane
][y
* td
->frame
->linesize
[td
->plane
]],
227 &s
->cur
->data
[td
->plane
][y
* refs
], td
->w
* df
);
233 static void filter(AVFilterContext
*ctx
, AVFrame
*dstpic
,
236 YADIFContext
*yadif
= ctx
->priv
;
237 ThreadData td
= { .frame
= dstpic
, .parity
= parity
, .tff
= tff
};
240 for (i
= 0; i
< yadif
->csp
->nb_components
; i
++) {
241 int w
= dstpic
->width
;
242 int h
= dstpic
->height
;
244 if (i
== 1 || i
== 2) {
245 w
>>= yadif
->csp
->log2_chroma_w
;
246 h
>>= yadif
->csp
->log2_chroma_h
;
254 ctx
->internal
->execute(ctx
, filter_slice
, &td
, NULL
, FFMIN(h
, ctx
->graph
->nb_threads
));
260 static AVFrame
*get_video_buffer(AVFilterLink
*link
, int w
, int h
)
263 int width
= FFALIGN(w
, 32);
264 int height
= FFALIGN(h
+ 2, 32);
267 frame
= ff_default_get_video_buffer(link
, width
, height
);
272 for (i
= 0; i
< 3; i
++)
273 frame
->data
[i
] += frame
->linesize
[i
];
278 static int return_frame(AVFilterContext
*ctx
, int is_second
)
280 YADIFContext
*yadif
= ctx
->priv
;
281 AVFilterLink
*link
= ctx
->outputs
[0];
284 if (yadif
->parity
== -1) {
285 tff
= yadif
->cur
->interlaced_frame
?
286 yadif
->cur
->top_field_first
: 1;
288 tff
= yadif
->parity
^ 1;
292 yadif
->out
= ff_get_video_buffer(link
, link
->w
, link
->h
);
294 return AVERROR(ENOMEM
);
296 av_frame_copy_props(yadif
->out
, yadif
->cur
);
297 yadif
->out
->interlaced_frame
= 0;
300 filter(ctx
, yadif
->out
, tff
^ !is_second
, tff
);
303 int64_t cur_pts
= yadif
->cur
->pts
;
304 int64_t next_pts
= yadif
->next
->pts
;
306 if (next_pts
!= AV_NOPTS_VALUE
&& cur_pts
!= AV_NOPTS_VALUE
) {
307 yadif
->out
->pts
= cur_pts
+ next_pts
;
309 yadif
->out
->pts
= AV_NOPTS_VALUE
;
312 ret
= ff_filter_frame(ctx
->outputs
[0], yadif
->out
);
314 yadif
->frame_pending
= (yadif
->mode
&1) && !is_second
;
318 static int filter_frame(AVFilterLink
*link
, AVFrame
*frame
)
320 AVFilterContext
*ctx
= link
->dst
;
321 YADIFContext
*yadif
= ctx
->priv
;
323 if (yadif
->frame_pending
)
324 return_frame(ctx
, 1);
327 av_frame_free(&yadif
->prev
);
328 yadif
->prev
= yadif
->cur
;
329 yadif
->cur
= yadif
->next
;
335 if (yadif
->auto_enable
&& !yadif
->cur
->interlaced_frame
) {
336 yadif
->out
= av_frame_clone(yadif
->cur
);
338 return AVERROR(ENOMEM
);
340 av_frame_free(&yadif
->prev
);
341 if (yadif
->out
->pts
!= AV_NOPTS_VALUE
)
342 yadif
->out
->pts
*= 2;
343 return ff_filter_frame(ctx
->outputs
[0], yadif
->out
);
347 !(yadif
->prev
= av_frame_clone(yadif
->cur
)))
348 return AVERROR(ENOMEM
);
350 yadif
->out
= ff_get_video_buffer(ctx
->outputs
[0], link
->w
, link
->h
);
352 return AVERROR(ENOMEM
);
354 av_frame_copy_props(yadif
->out
, yadif
->cur
);
355 yadif
->out
->interlaced_frame
= 0;
357 if (yadif
->out
->pts
!= AV_NOPTS_VALUE
)
358 yadif
->out
->pts
*= 2;
360 return return_frame(ctx
, 0);
363 static int request_frame(AVFilterLink
*link
)
365 AVFilterContext
*ctx
= link
->src
;
366 YADIFContext
*yadif
= ctx
->priv
;
368 if (yadif
->frame_pending
) {
369 return_frame(ctx
, 1);
379 ret
= ff_request_frame(link
->src
->inputs
[0]);
381 if (ret
== AVERROR_EOF
&& yadif
->next
) {
382 AVFrame
*next
= av_frame_clone(yadif
->next
);
385 return AVERROR(ENOMEM
);
387 next
->pts
= yadif
->next
->pts
* 2 - yadif
->cur
->pts
;
389 filter_frame(link
->src
->inputs
[0], next
);
391 } else if (ret
< 0) {
394 } while (!yadif
->cur
);
399 static int poll_frame(AVFilterLink
*link
)
401 YADIFContext
*yadif
= link
->src
->priv
;
404 if (yadif
->frame_pending
)
407 val
= ff_poll_frame(link
->src
->inputs
[0]);
411 //FIXME change API to not require this red tape
412 if (val
== 1 && !yadif
->next
) {
413 if ((ret
= ff_request_frame(link
->src
->inputs
[0])) < 0)
415 val
= ff_poll_frame(link
->src
->inputs
[0]);
419 assert(yadif
->next
|| !val
);
421 if (yadif
->auto_enable
&& yadif
->next
&& !yadif
->next
->interlaced_frame
)
424 return val
* ((yadif
->mode
&1)+1);
427 static av_cold
void uninit(AVFilterContext
*ctx
)
429 YADIFContext
*yadif
= ctx
->priv
;
431 if (yadif
->prev
) av_frame_free(&yadif
->prev
);
432 if (yadif
->cur
) av_frame_free(&yadif
->cur
);
433 if (yadif
->next
) av_frame_free(&yadif
->next
);
436 static int query_formats(AVFilterContext
*ctx
)
438 static const enum AVPixelFormat pix_fmts
[] = {
448 AV_NE( AV_PIX_FMT_GRAY16BE
, AV_PIX_FMT_GRAY16LE
),
451 AV_NE( AV_PIX_FMT_YUV420P10BE
, AV_PIX_FMT_YUV420P10LE
),
452 AV_NE( AV_PIX_FMT_YUV422P10BE
, AV_PIX_FMT_YUV422P10LE
),
453 AV_NE( AV_PIX_FMT_YUV444P10BE
, AV_PIX_FMT_YUV444P10LE
),
454 AV_NE( AV_PIX_FMT_YUV420P16BE
, AV_PIX_FMT_YUV420P16LE
),
455 AV_NE( AV_PIX_FMT_YUV422P16BE
, AV_PIX_FMT_YUV422P16LE
),
456 AV_NE( AV_PIX_FMT_YUV444P16BE
, AV_PIX_FMT_YUV444P16LE
),
461 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
466 static int config_props(AVFilterLink
*link
)
468 YADIFContext
*s
= link
->src
->priv
;
470 link
->time_base
.num
= link
->src
->inputs
[0]->time_base
.num
;
471 link
->time_base
.den
= link
->src
->inputs
[0]->time_base
.den
* 2;
472 link
->w
= link
->src
->inputs
[0]->w
;
473 link
->h
= link
->src
->inputs
[0]->h
;
476 link
->frame_rate
= av_mul_q(link
->src
->inputs
[0]->frame_rate
,
479 s
->csp
= av_pix_fmt_desc_get(link
->format
);
480 if (s
->csp
->comp
[0].depth
> 8) {
481 s
->filter_line
= filter_line_c_16bit
;
482 s
->filter_edges
= filter_edges_16bit
;
484 s
->filter_line
= filter_line_c
;
485 s
->filter_edges
= filter_edges
;
488 ff_yadif_init_x86(s
);
494 #define OFFSET(x) offsetof(YADIFContext, x)
495 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM
496 static const AVOption options
[] = {
497 { "mode", NULL
, OFFSET(mode
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 3, FLAGS
},
498 { "parity", NULL
, OFFSET(parity
), AV_OPT_TYPE_INT
, { .i64
= -1 }, -1, 1, FLAGS
, "parity" },
499 { "auto", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= -1 }, .unit
= "parity" },
500 { "tff", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= 0 }, .unit
= "parity" },
501 { "bff", NULL
, 0, AV_OPT_TYPE_CONST
, { .i64
= 1 }, .unit
= "parity" },
502 { "auto", NULL
, OFFSET(auto_enable
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, 1, FLAGS
},
506 static const AVClass yadif_class
= {
507 .class_name
= "yadif",
508 .item_name
= av_default_item_name
,
510 .version
= LIBAVUTIL_VERSION_INT
,
513 static const AVFilterPad avfilter_vf_yadif_inputs
[] = {
516 .type
= AVMEDIA_TYPE_VIDEO
,
517 .get_video_buffer
= get_video_buffer
,
518 .filter_frame
= filter_frame
,
523 static const AVFilterPad avfilter_vf_yadif_outputs
[] = {
526 .type
= AVMEDIA_TYPE_VIDEO
,
527 .poll_frame
= poll_frame
,
528 .request_frame
= request_frame
,
529 .config_props
= config_props
,
534 AVFilter ff_vf_yadif
= {
536 .description
= NULL_IF_CONFIG_SMALL("Deinterlace the input image"),
538 .priv_size
= sizeof(YADIFContext
),
539 .priv_class
= &yadif_class
,
541 .query_formats
= query_formats
,
543 .inputs
= avfilter_vf_yadif_inputs
,
545 .outputs
= avfilter_vf_yadif_outputs
,
547 .flags
= AVFILTER_FLAG_SLICE_THREADS
,