1/* 2 * Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at> 3 * 2010 James Darnley <james.darnley@gmail.com> 4 * 5 * This file is part of Libav. 6 * 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. 11 * 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. 16 * 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. 20 */ 21 22#include "libavutil/cpu.h" 23#include "libavutil/common.h" 24#include "libavutil/pixdesc.h" 25#include "avfilter.h" 26#include "yadif.h" 27 28#undef NDEBUG 29#include <assert.h> 30 31typedef struct { 32 /** 33 * 0: send 1 frame for each frame 34 * 1: send 1 frame for each field 35 * 2: like 0 but skips spatial interlacing check 36 * 3: like 1 but skips spatial interlacing check 37 */ 38 int mode; 39 40 /** 41 * 0: top field first 42 * 1: bottom field first 43 * -1: auto-detection 44 */ 45 int parity; 46 47 int frame_pending; 48 49 /** 50 * 0: deinterlace all frames 51 * 1: only deinterlace frames marked as interlaced 52 */ 53 int auto_enable; 54 55 AVFilterBufferRef *cur; 56 AVFilterBufferRef *next; 57 AVFilterBufferRef *prev; 58 AVFilterBufferRef *out; 59 void (*filter_line)(uint8_t *dst, 60 uint8_t *prev, uint8_t *cur, uint8_t *next, 61 int w, int prefs, int mrefs, int parity, int mode); 62 63 const AVPixFmtDescriptor *csp; 64} YADIFContext; 65 66#define CHECK(j)\ 67 { int score = FFABS(cur[mrefs-1+(j)] - cur[prefs-1-(j)])\ 68 + FFABS(cur[mrefs +(j)] - cur[prefs -(j)])\ 69 + FFABS(cur[mrefs+1+(j)] - cur[prefs+1-(j)]);\ 70 if (score < spatial_score) {\ 71 spatial_score= score;\ 72 spatial_pred= (cur[mrefs +(j)] + cur[prefs -(j)])>>1;\ 73 74#define FILTER \ 75 for (x = 0; x < w; x++) { \ 76 int c = cur[mrefs]; \ 77 int d = (prev2[0] + next2[0])>>1; \ 78 int e = cur[prefs]; \ 79 int temporal_diff0 = FFABS(prev2[0] - next2[0]); \ 80 int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \ 81 int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \ 82 int diff = FFMAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2); \ 83 int spatial_pred = (c+e)>>1; \ 84 int spatial_score = FFABS(cur[mrefs-1] - cur[prefs-1]) + FFABS(c-e) \ 85 + FFABS(cur[mrefs+1] - cur[prefs+1]) - 1; \ 86 \ 87 CHECK(-1) CHECK(-2) }} }} \ 88 CHECK( 1) CHECK( 2) }} }} \ 89 \ 90 if (mode < 2) { \ 91 int b = (prev2[2*mrefs] + next2[2*mrefs])>>1; \ 92 int f = (prev2[2*prefs] + next2[2*prefs])>>1; \ 93 int max = FFMAX3(d-e, d-c, FFMIN(b-c, f-e)); \ 94 int min = FFMIN3(d-e, d-c, FFMAX(b-c, f-e)); \ 95 \ 96 diff = FFMAX3(diff, min, -max); \ 97 } \ 98 \ 99 if (spatial_pred > d + diff) \ 100 spatial_pred = d + diff; \ 101 else if (spatial_pred < d - diff) \ 102 spatial_pred = d - diff; \ 103 \ 104 dst[0] = spatial_pred; \ 105 \ 106 dst++; \ 107 cur++; \ 108 prev++; \ 109 next++; \ 110 prev2++; \ 111 next2++; \ 112 } 113 114static void filter_line_c(uint8_t *dst, 115 uint8_t *prev, uint8_t *cur, uint8_t *next, 116 int w, int prefs, int mrefs, int parity, int mode) 117{ 118 int x; 119 uint8_t *prev2 = parity ? prev : cur ; 120 uint8_t *next2 = parity ? cur : next; 121 122 FILTER 123} 124 125static void filter_line_c_16bit(uint16_t *dst, 126 uint16_t *prev, uint16_t *cur, uint16_t *next, 127 int w, int prefs, int mrefs, int parity, int mode) 128{ 129 int x; 130 uint16_t *prev2 = parity ? prev : cur ; 131 uint16_t *next2 = parity ? cur : next; 132 mrefs /= 2; 133 prefs /= 2; 134 135 FILTER 136} 137 138static void filter(AVFilterContext *ctx, AVFilterBufferRef *dstpic, 139 int parity, int tff) 140{ 141 YADIFContext *yadif = ctx->priv; 142 int y, i; 143 144 for (i = 0; i < yadif->csp->nb_components; i++) { 145 int w = dstpic->video->w; 146 int h = dstpic->video->h; 147 int refs = yadif->cur->linesize[i]; 148 int df = (yadif->csp->comp[i].depth_minus1 + 8) / 8; 149 150 if (i == 1 || i == 2) { 151 /* Why is this not part of the per-plane description thing? */ 152 w >>= yadif->csp->log2_chroma_w; 153 h >>= yadif->csp->log2_chroma_h; 154 } 155 156 for (y = 0; y < h; y++) { 157 if ((y ^ parity) & 1) { 158 uint8_t *prev = &yadif->prev->data[i][y*refs]; 159 uint8_t *cur = &yadif->cur ->data[i][y*refs]; 160 uint8_t *next = &yadif->next->data[i][y*refs]; 161 uint8_t *dst = &dstpic->data[i][y*dstpic->linesize[i]]; 162 int mode = y==1 || y+2==h ? 2 : yadif->mode; 163 yadif->filter_line(dst, prev, cur, next, w, y+1<h ? refs : -refs, y ? -refs : refs, parity ^ tff, mode); 164 } else { 165 memcpy(&dstpic->data[i][y*dstpic->linesize[i]], 166 &yadif->cur->data[i][y*refs], w*df); 167 } 168 } 169 } 170#if HAVE_MMX 171 __asm__ volatile("emms \n\t" : : : "memory"); 172#endif 173} 174 175static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h) 176{ 177 AVFilterBufferRef *picref; 178 int width = FFALIGN(w, 32); 179 int height= FFALIGN(h+2, 32); 180 int i; 181 182 picref = avfilter_default_get_video_buffer(link, perms, width, height); 183 184 picref->video->w = w; 185 picref->video->h = h; 186 187 for (i = 0; i < 3; i++) 188 picref->data[i] += picref->linesize[i]; 189 190 return picref; 191} 192 193static void return_frame(AVFilterContext *ctx, int is_second) 194{ 195 YADIFContext *yadif = ctx->priv; 196 AVFilterLink *link= ctx->outputs[0]; 197 int tff; 198 199 if (yadif->parity == -1) { 200 tff = yadif->cur->video->interlaced ? 201 yadif->cur->video->top_field_first : 1; 202 } else { 203 tff = yadif->parity^1; 204 } 205 206 if (is_second) { 207 yadif->out = avfilter_get_video_buffer(link, AV_PERM_WRITE | AV_PERM_PRESERVE | 208 AV_PERM_REUSE, link->w, link->h); 209 avfilter_copy_buffer_ref_props(yadif->out, yadif->cur); 210 yadif->out->video->interlaced = 0; 211 } 212 213 if (!yadif->csp) 214 yadif->csp = &av_pix_fmt_descriptors[link->format]; 215 if (yadif->csp->comp[0].depth_minus1 / 8 == 1) 216 yadif->filter_line = filter_line_c_16bit; 217 218 filter(ctx, yadif->out, tff ^ !is_second, tff); 219 220 if (is_second) { 221 if (yadif->next->pts != AV_NOPTS_VALUE && 222 yadif->cur->pts != AV_NOPTS_VALUE) { 223 yadif->out->pts = 224 (yadif->next->pts&yadif->cur->pts) + 225 ((yadif->next->pts^yadif->cur->pts)>>1); 226 } else { 227 yadif->out->pts = AV_NOPTS_VALUE; 228 } 229 avfilter_start_frame(ctx->outputs[0], yadif->out); 230 } 231 avfilter_draw_slice(ctx->outputs[0], 0, link->h, 1); 232 avfilter_end_frame(ctx->outputs[0]); 233 234 yadif->frame_pending = (yadif->mode&1) && !is_second; 235} 236 237static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) 238{ 239 AVFilterContext *ctx = link->dst; 240 YADIFContext *yadif = ctx->priv; 241 242 if (yadif->frame_pending) 243 return_frame(ctx, 1); 244 245 if (yadif->prev) 246 avfilter_unref_buffer(yadif->prev); 247 yadif->prev = yadif->cur; 248 yadif->cur = yadif->next; 249 yadif->next = picref; 250 251 if (!yadif->cur) 252 return; 253 254 if (yadif->auto_enable && !yadif->cur->video->interlaced) { 255 yadif->out = avfilter_ref_buffer(yadif->cur, AV_PERM_READ); 256 avfilter_unref_buffer(yadif->prev); 257 yadif->prev = NULL; 258 avfilter_start_frame(ctx->outputs[0], yadif->out); 259 return; 260 } 261 262 if (!yadif->prev) 263 yadif->prev = avfilter_ref_buffer(yadif->cur, AV_PERM_READ); 264 265 yadif->out = avfilter_get_video_buffer(ctx->outputs[0], AV_PERM_WRITE | AV_PERM_PRESERVE | 266 AV_PERM_REUSE, link->w, link->h); 267 268 avfilter_copy_buffer_ref_props(yadif->out, yadif->cur); 269 yadif->out->video->interlaced = 0; 270 avfilter_start_frame(ctx->outputs[0], yadif->out); 271} 272 273static void end_frame(AVFilterLink *link) 274{ 275 AVFilterContext *ctx = link->dst; 276 YADIFContext *yadif = ctx->priv; 277 278 if (!yadif->out) 279 return; 280 281 if (yadif->auto_enable && !yadif->cur->video->interlaced) { 282 avfilter_draw_slice(ctx->outputs[0], 0, link->h, 1); 283 avfilter_end_frame(ctx->outputs[0]); 284 return; 285 } 286 287 return_frame(ctx, 0); 288} 289 290static int request_frame(AVFilterLink *link) 291{ 292 AVFilterContext *ctx = link->src; 293 YADIFContext *yadif = ctx->priv; 294 295 if (yadif->frame_pending) { 296 return_frame(ctx, 1); 297 return 0; 298 } 299 300 do { 301 int ret; 302 303 if ((ret = avfilter_request_frame(link->src->inputs[0]))) 304 return ret; 305 } while (!yadif->cur); 306 307 return 0; 308} 309 310static int poll_frame(AVFilterLink *link) 311{ 312 YADIFContext *yadif = link->src->priv; 313 int ret, val; 314 315 if (yadif->frame_pending) 316 return 1; 317 318 val = avfilter_poll_frame(link->src->inputs[0]); 319 320 if (val==1 && !yadif->next) { //FIXME change API to not requre this red tape 321 if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0) 322 return ret; 323 val = avfilter_poll_frame(link->src->inputs[0]); 324 } 325 assert(yadif->next || !val); 326 327 if (yadif->auto_enable && yadif->next && !yadif->next->video->interlaced) 328 return val; 329 330 return val * ((yadif->mode&1)+1); 331} 332 333static av_cold void uninit(AVFilterContext *ctx) 334{ 335 YADIFContext *yadif = ctx->priv; 336 337 if (yadif->prev) avfilter_unref_buffer(yadif->prev); 338 if (yadif->cur ) avfilter_unref_buffer(yadif->cur ); 339 if (yadif->next) avfilter_unref_buffer(yadif->next); 340} 341 342static int query_formats(AVFilterContext *ctx) 343{ 344 static const enum PixelFormat pix_fmts[] = { 345 PIX_FMT_YUV420P, 346 PIX_FMT_YUV422P, 347 PIX_FMT_YUV444P, 348 PIX_FMT_YUV410P, 349 PIX_FMT_YUV411P, 350 PIX_FMT_GRAY8, 351 PIX_FMT_YUVJ420P, 352 PIX_FMT_YUVJ422P, 353 PIX_FMT_YUVJ444P, 354 AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ), 355 PIX_FMT_YUV440P, 356 PIX_FMT_YUVJ440P, 357 AV_NE( PIX_FMT_YUV420P10BE, PIX_FMT_YUV420P10LE ), 358 AV_NE( PIX_FMT_YUV422P10BE, PIX_FMT_YUV422P10LE ), 359 AV_NE( PIX_FMT_YUV444P10BE, PIX_FMT_YUV444P10LE ), 360 AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ), 361 AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ), 362 AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ), 363 PIX_FMT_YUVA420P, 364 PIX_FMT_NONE 365 }; 366 367 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); 368 369 return 0; 370} 371 372static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 373{ 374 YADIFContext *yadif = ctx->priv; 375 av_unused int cpu_flags = av_get_cpu_flags(); 376 377 yadif->mode = 0; 378 yadif->parity = -1; 379 yadif->auto_enable = 0; 380 yadif->csp = NULL; 381 382 if (args) sscanf(args, "%d:%d:%d", &yadif->mode, &yadif->parity, &yadif->auto_enable); 383 384 yadif->filter_line = filter_line_c; 385 if (HAVE_SSSE3 && cpu_flags & AV_CPU_FLAG_SSSE3) 386 yadif->filter_line = ff_yadif_filter_line_ssse3; 387 else if (HAVE_SSE && cpu_flags & AV_CPU_FLAG_SSE2) 388 yadif->filter_line = ff_yadif_filter_line_sse2; 389 else if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX) 390 yadif->filter_line = ff_yadif_filter_line_mmx; 391 392 av_log(ctx, AV_LOG_INFO, "mode:%d parity:%d auto_enable:%d\n", yadif->mode, yadif->parity, yadif->auto_enable); 393 394 return 0; 395} 396 397static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { } 398 399AVFilter avfilter_vf_yadif = { 400 .name = "yadif", 401 .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image"), 402 403 .priv_size = sizeof(YADIFContext), 404 .init = init, 405 .uninit = uninit, 406 .query_formats = query_formats, 407 408 .inputs = (AVFilterPad[]) {{ .name = "default", 409 .type = AVMEDIA_TYPE_VIDEO, 410 .start_frame = start_frame, 411 .get_video_buffer = get_video_buffer, 412 .draw_slice = null_draw_slice, 413 .end_frame = end_frame, }, 414 { .name = NULL}}, 415 416 .outputs = (AVFilterPad[]) {{ .name = "default", 417 .type = AVMEDIA_TYPE_VIDEO, 418 .poll_frame = poll_frame, 419 .request_frame = request_frame, }, 420 { .name = NULL}}, 421}; 422