Libav 0.7.1
|
00001 /* 00002 * Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at> 00003 * 2010 James Darnley <james.darnley@gmail.com> 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License along 00018 * with Libav; if not, write to the Free Software Foundation, Inc., 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00020 */ 00021 00022 #include "libavutil/cpu.h" 00023 #include "libavutil/common.h" 00024 #include "libavutil/pixdesc.h" 00025 #include "avfilter.h" 00026 #include "yadif.h" 00027 00028 #undef NDEBUG 00029 #include <assert.h> 00030 00031 typedef struct { 00038 int mode; 00039 00045 int parity; 00046 00047 int frame_pending; 00048 00049 AVFilterBufferRef *cur; 00050 AVFilterBufferRef *next; 00051 AVFilterBufferRef *prev; 00052 AVFilterBufferRef *out; 00053 void (*filter_line)(uint8_t *dst, 00054 uint8_t *prev, uint8_t *cur, uint8_t *next, 00055 int w, int prefs, int mrefs, int parity, int mode); 00056 00057 const AVPixFmtDescriptor *csp; 00058 } YADIFContext; 00059 00060 #define CHECK(j)\ 00061 { int score = FFABS(cur[mrefs-1+(j)] - cur[prefs-1-(j)])\ 00062 + FFABS(cur[mrefs +(j)] - cur[prefs -(j)])\ 00063 + FFABS(cur[mrefs+1+(j)] - cur[prefs+1-(j)]);\ 00064 if (score < spatial_score) {\ 00065 spatial_score= score;\ 00066 spatial_pred= (cur[mrefs +(j)] + cur[prefs -(j)])>>1;\ 00067 00068 #define FILTER \ 00069 for (x = 0; x < w; x++) { \ 00070 int c = cur[mrefs]; \ 00071 int d = (prev2[0] + next2[0])>>1; \ 00072 int e = cur[prefs]; \ 00073 int temporal_diff0 = FFABS(prev2[0] - next2[0]); \ 00074 int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1; \ 00075 int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1; \ 00076 int diff = FFMAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2); \ 00077 int spatial_pred = (c+e)>>1; \ 00078 int spatial_score = FFABS(cur[mrefs-1] - cur[prefs-1]) + FFABS(c-e) \ 00079 + FFABS(cur[mrefs+1] - cur[prefs+1]) - 1; \ 00080 \ 00081 CHECK(-1) CHECK(-2) }} }} \ 00082 CHECK( 1) CHECK( 2) }} }} \ 00083 \ 00084 if (mode < 2) { \ 00085 int b = (prev2[2*mrefs] + next2[2*mrefs])>>1; \ 00086 int f = (prev2[2*prefs] + next2[2*prefs])>>1; \ 00087 int max = FFMAX3(d-e, d-c, FFMIN(b-c, f-e)); \ 00088 int min = FFMIN3(d-e, d-c, FFMAX(b-c, f-e)); \ 00089 \ 00090 diff = FFMAX3(diff, min, -max); \ 00091 } \ 00092 \ 00093 if (spatial_pred > d + diff) \ 00094 spatial_pred = d + diff; \ 00095 else if (spatial_pred < d - diff) \ 00096 spatial_pred = d - diff; \ 00097 \ 00098 dst[0] = spatial_pred; \ 00099 \ 00100 dst++; \ 00101 cur++; \ 00102 prev++; \ 00103 next++; \ 00104 prev2++; \ 00105 next2++; \ 00106 } 00107 00108 static void filter_line_c(uint8_t *dst, 00109 uint8_t *prev, uint8_t *cur, uint8_t *next, 00110 int w, int prefs, int mrefs, int parity, int mode) 00111 { 00112 int x; 00113 uint8_t *prev2 = parity ? prev : cur ; 00114 uint8_t *next2 = parity ? cur : next; 00115 00116 FILTER 00117 } 00118 00119 static void filter_line_c_16bit(uint16_t *dst, 00120 uint16_t *prev, uint16_t *cur, uint16_t *next, 00121 int w, int prefs, int mrefs, int parity, int mode) 00122 { 00123 int x; 00124 uint16_t *prev2 = parity ? prev : cur ; 00125 uint16_t *next2 = parity ? cur : next; 00126 mrefs /= 2; 00127 prefs /= 2; 00128 00129 FILTER 00130 } 00131 00132 static void filter(AVFilterContext *ctx, AVFilterBufferRef *dstpic, 00133 int parity, int tff) 00134 { 00135 YADIFContext *yadif = ctx->priv; 00136 int y, i; 00137 00138 for (i = 0; i < yadif->csp->nb_components; i++) { 00139 int w = dstpic->video->w; 00140 int h = dstpic->video->h; 00141 int refs = yadif->cur->linesize[i]; 00142 int df = (yadif->csp->comp[i].depth_minus1+1) / 8; 00143 00144 if (i) { 00145 /* Why is this not part of the per-plane description thing? */ 00146 w >>= yadif->csp->log2_chroma_w; 00147 h >>= yadif->csp->log2_chroma_h; 00148 } 00149 00150 for (y = 0; y < h; y++) { 00151 if ((y ^ parity) & 1) { 00152 uint8_t *prev = &yadif->prev->data[i][y*refs]; 00153 uint8_t *cur = &yadif->cur ->data[i][y*refs]; 00154 uint8_t *next = &yadif->next->data[i][y*refs]; 00155 uint8_t *dst = &dstpic->data[i][y*dstpic->linesize[i]]; 00156 int mode = y==1 || y+2==h ? 2 : yadif->mode; 00157 yadif->filter_line(dst, prev, cur, next, w, y+1<h ? refs : -refs, y ? -refs : refs, parity ^ tff, mode); 00158 } else { 00159 memcpy(&dstpic->data[i][y*dstpic->linesize[i]], 00160 &yadif->cur->data[i][y*refs], w*df); 00161 } 00162 } 00163 } 00164 #if HAVE_MMX 00165 __asm__ volatile("emms \n\t" : : : "memory"); 00166 #endif 00167 } 00168 00169 static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h) 00170 { 00171 AVFilterBufferRef *picref; 00172 int width = FFALIGN(w, 32); 00173 int height= FFALIGN(h+2, 32); 00174 int i; 00175 00176 picref = avfilter_default_get_video_buffer(link, perms, width, height); 00177 00178 picref->video->w = w; 00179 picref->video->h = h; 00180 00181 for (i = 0; i < 3; i++) 00182 picref->data[i] += picref->linesize[i]; 00183 00184 return picref; 00185 } 00186 00187 static void return_frame(AVFilterContext *ctx, int is_second) 00188 { 00189 YADIFContext *yadif = ctx->priv; 00190 AVFilterLink *link= ctx->outputs[0]; 00191 int tff; 00192 00193 if (yadif->parity == -1) { 00194 tff = yadif->cur->video->interlaced ? 00195 yadif->cur->video->top_field_first : 1; 00196 } else { 00197 tff = yadif->parity^1; 00198 } 00199 00200 if (is_second) { 00201 yadif->out = avfilter_get_video_buffer(link, AV_PERM_WRITE | AV_PERM_PRESERVE | 00202 AV_PERM_REUSE, link->w, link->h); 00203 avfilter_copy_buffer_ref_props(yadif->out, yadif->cur); 00204 yadif->out->video->interlaced = 0; 00205 } 00206 00207 if (!yadif->csp) 00208 yadif->csp = &av_pix_fmt_descriptors[link->format]; 00209 if (yadif->csp->comp[0].depth_minus1 == 15) 00210 yadif->filter_line = filter_line_c_16bit; 00211 00212 filter(ctx, yadif->out, tff ^ !is_second, tff); 00213 00214 if (is_second) { 00215 if (yadif->next->pts != AV_NOPTS_VALUE && 00216 yadif->cur->pts != AV_NOPTS_VALUE) { 00217 yadif->out->pts = 00218 (yadif->next->pts&yadif->cur->pts) + 00219 ((yadif->next->pts^yadif->cur->pts)>>1); 00220 } else { 00221 yadif->out->pts = AV_NOPTS_VALUE; 00222 } 00223 avfilter_start_frame(ctx->outputs[0], yadif->out); 00224 } 00225 avfilter_draw_slice(ctx->outputs[0], 0, link->h, 1); 00226 avfilter_end_frame(ctx->outputs[0]); 00227 00228 yadif->frame_pending = (yadif->mode&1) && !is_second; 00229 } 00230 00231 static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) 00232 { 00233 AVFilterContext *ctx = link->dst; 00234 YADIFContext *yadif = ctx->priv; 00235 00236 if (yadif->frame_pending) 00237 return_frame(ctx, 1); 00238 00239 if (yadif->prev) 00240 avfilter_unref_buffer(yadif->prev); 00241 yadif->prev = yadif->cur; 00242 yadif->cur = yadif->next; 00243 yadif->next = picref; 00244 00245 if (!yadif->cur) 00246 return; 00247 00248 if (!yadif->prev) 00249 yadif->prev = avfilter_ref_buffer(yadif->cur, AV_PERM_READ); 00250 00251 yadif->out = avfilter_get_video_buffer(ctx->outputs[0], AV_PERM_WRITE | AV_PERM_PRESERVE | 00252 AV_PERM_REUSE, link->w, link->h); 00253 00254 avfilter_copy_buffer_ref_props(yadif->out, yadif->cur); 00255 yadif->out->video->interlaced = 0; 00256 avfilter_start_frame(ctx->outputs[0], yadif->out); 00257 } 00258 00259 static void end_frame(AVFilterLink *link) 00260 { 00261 AVFilterContext *ctx = link->dst; 00262 YADIFContext *yadif = ctx->priv; 00263 00264 if (!yadif->out) 00265 return; 00266 00267 return_frame(ctx, 0); 00268 } 00269 00270 static int request_frame(AVFilterLink *link) 00271 { 00272 AVFilterContext *ctx = link->src; 00273 YADIFContext *yadif = ctx->priv; 00274 00275 if (yadif->frame_pending) { 00276 return_frame(ctx, 1); 00277 return 0; 00278 } 00279 00280 do { 00281 int ret; 00282 00283 if ((ret = avfilter_request_frame(link->src->inputs[0]))) 00284 return ret; 00285 } while (!yadif->cur); 00286 00287 return 0; 00288 } 00289 00290 static int poll_frame(AVFilterLink *link) 00291 { 00292 YADIFContext *yadif = link->src->priv; 00293 int ret, val; 00294 00295 if (yadif->frame_pending) 00296 return 1; 00297 00298 val = avfilter_poll_frame(link->src->inputs[0]); 00299 00300 if (val==1 && !yadif->next) { //FIXME change API to not requre this red tape 00301 if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0) 00302 return ret; 00303 val = avfilter_poll_frame(link->src->inputs[0]); 00304 } 00305 assert(yadif->next || !val); 00306 00307 return val * ((yadif->mode&1)+1); 00308 } 00309 00310 static av_cold void uninit(AVFilterContext *ctx) 00311 { 00312 YADIFContext *yadif = ctx->priv; 00313 00314 if (yadif->prev) avfilter_unref_buffer(yadif->prev); 00315 if (yadif->cur ) avfilter_unref_buffer(yadif->cur ); 00316 if (yadif->next) avfilter_unref_buffer(yadif->next); 00317 } 00318 00319 static int query_formats(AVFilterContext *ctx) 00320 { 00321 static const enum PixelFormat pix_fmts[] = { 00322 PIX_FMT_YUV420P, 00323 PIX_FMT_YUV422P, 00324 PIX_FMT_YUV444P, 00325 PIX_FMT_YUV410P, 00326 PIX_FMT_YUV411P, 00327 PIX_FMT_GRAY8, 00328 PIX_FMT_YUVJ420P, 00329 PIX_FMT_YUVJ422P, 00330 PIX_FMT_YUVJ444P, 00331 AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ), 00332 PIX_FMT_YUV440P, 00333 PIX_FMT_YUVJ440P, 00334 AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ), 00335 AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ), 00336 AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ), 00337 PIX_FMT_NONE 00338 }; 00339 00340 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); 00341 00342 return 0; 00343 } 00344 00345 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) 00346 { 00347 YADIFContext *yadif = ctx->priv; 00348 av_unused int cpu_flags = av_get_cpu_flags(); 00349 00350 yadif->mode = 0; 00351 yadif->parity = -1; 00352 yadif->csp = NULL; 00353 00354 if (args) sscanf(args, "%d:%d", &yadif->mode, &yadif->parity); 00355 00356 yadif->filter_line = filter_line_c; 00357 if (HAVE_SSSE3 && cpu_flags & AV_CPU_FLAG_SSSE3) 00358 yadif->filter_line = ff_yadif_filter_line_ssse3; 00359 else if (HAVE_SSE && cpu_flags & AV_CPU_FLAG_SSE2) 00360 yadif->filter_line = ff_yadif_filter_line_sse2; 00361 else if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX) 00362 yadif->filter_line = ff_yadif_filter_line_mmx; 00363 00364 av_log(ctx, AV_LOG_INFO, "mode:%d parity:%d\n", yadif->mode, yadif->parity); 00365 00366 return 0; 00367 } 00368 00369 static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { } 00370 00371 AVFilter avfilter_vf_yadif = { 00372 .name = "yadif", 00373 .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image"), 00374 00375 .priv_size = sizeof(YADIFContext), 00376 .init = init, 00377 .uninit = uninit, 00378 .query_formats = query_formats, 00379 00380 .inputs = (AVFilterPad[]) {{ .name = "default", 00381 .type = AVMEDIA_TYPE_VIDEO, 00382 .start_frame = start_frame, 00383 .get_video_buffer = get_video_buffer, 00384 .draw_slice = null_draw_slice, 00385 .end_frame = end_frame, }, 00386 { .name = NULL}}, 00387 00388 .outputs = (AVFilterPad[]) {{ .name = "default", 00389 .type = AVMEDIA_TYPE_VIDEO, 00390 .poll_frame = poll_frame, 00391 .request_frame = request_frame, }, 00392 { .name = NULL}}, 00393 };