00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "libavutil/cpu.h"
00022 #include "libavutil/common.h"
00023 #include "avfilter.h"
00024 #include "yadif.h"
00025
00026 #undef NDEBUG
00027 #include <assert.h>
00028
00029 typedef struct {
00036 int mode;
00037
00043 int parity;
00044
00045 int frame_pending;
00046
00047 AVFilterBufferRef *cur;
00048 AVFilterBufferRef *next;
00049 AVFilterBufferRef *prev;
00050 AVFilterBufferRef *out;
00051 void (*filter_line)(uint8_t *dst,
00052 uint8_t *prev, uint8_t *cur, uint8_t *next,
00053 int w, int prefs, int mrefs, int parity, int mode);
00054 } YADIFContext;
00055
00056 static void filter_line_c(uint8_t *dst,
00057 uint8_t *prev, uint8_t *cur, uint8_t *next,
00058 int w, int prefs, int mrefs, int parity, int mode)
00059 {
00060 int x;
00061 uint8_t *prev2 = parity ? prev : cur ;
00062 uint8_t *next2 = parity ? cur : next;
00063 for (x = 0; x < w; x++) {
00064 int c = cur[mrefs];
00065 int d = (prev2[0] + next2[0])>>1;
00066 int e = cur[prefs];
00067 int temporal_diff0 = FFABS(prev2[0] - next2[0]);
00068 int temporal_diff1 =(FFABS(prev[mrefs] - c) + FFABS(prev[prefs] - e) )>>1;
00069 int temporal_diff2 =(FFABS(next[mrefs] - c) + FFABS(next[prefs] - e) )>>1;
00070 int diff = FFMAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2);
00071 int spatial_pred = (c+e)>>1;
00072 int spatial_score = FFABS(cur[mrefs-1] - cur[prefs-1]) + FFABS(c-e)
00073 + FFABS(cur[mrefs+1] - cur[prefs+1]) - 1;
00074
00075 #define CHECK(j)\
00076 { int score = FFABS(cur[mrefs-1+(j)] - cur[prefs-1-(j)])\
00077 + FFABS(cur[mrefs +(j)] - cur[prefs -(j)])\
00078 + FFABS(cur[mrefs+1+(j)] - cur[prefs+1-(j)]);\
00079 if (score < spatial_score) {\
00080 spatial_score= score;\
00081 spatial_pred= (cur[mrefs +(j)] + cur[prefs -(j)])>>1;\
00082
00083 CHECK(-1) CHECK(-2) }} }}
00084 CHECK( 1) CHECK( 2) }} }}
00085
00086 if (mode < 2) {
00087 int b = (prev2[2*mrefs] + next2[2*mrefs])>>1;
00088 int f = (prev2[2*prefs] + next2[2*prefs])>>1;
00089 #if 0
00090 int a = cur[-3*refs];
00091 int g = cur[+3*refs];
00092 int max = FFMAX3(d-e, d-c, FFMIN3(FFMAX(b-c,f-e),FFMAX(b-c,b-a),FFMAX(f-g,f-e)) );
00093 int min = FFMIN3(d-e, d-c, FFMAX3(FFMIN(b-c,f-e),FFMIN(b-c,b-a),FFMIN(f-g,f-e)) );
00094 #else
00095 int max = FFMAX3(d-e, d-c, FFMIN(b-c, f-e));
00096 int min = FFMIN3(d-e, d-c, FFMAX(b-c, f-e));
00097 #endif
00098
00099 diff = FFMAX3(diff, min, -max);
00100 }
00101
00102 if (spatial_pred > d + diff)
00103 spatial_pred = d + diff;
00104 else if (spatial_pred < d - diff)
00105 spatial_pred = d - diff;
00106
00107 dst[0] = spatial_pred;
00108
00109 dst++;
00110 cur++;
00111 prev++;
00112 next++;
00113 prev2++;
00114 next2++;
00115 }
00116 }
00117
00118 static void filter(AVFilterContext *ctx, AVFilterBufferRef *dstpic,
00119 int parity, int tff)
00120 {
00121 YADIFContext *yadif = ctx->priv;
00122 int y, i;
00123
00124 for (i = 0; i < 3; i++) {
00125 int is_chroma = !!i;
00126 int w = dstpic->video->w >> is_chroma;
00127 int h = dstpic->video->h >> is_chroma;
00128 int refs = yadif->cur->linesize[i];
00129
00130 for (y = 0; y < h; y++) {
00131 if ((y ^ parity) & 1) {
00132 uint8_t *prev = &yadif->prev->data[i][y*refs];
00133 uint8_t *cur = &yadif->cur ->data[i][y*refs];
00134 uint8_t *next = &yadif->next->data[i][y*refs];
00135 uint8_t *dst = &dstpic->data[i][y*dstpic->linesize[i]];
00136 int mode = y==1 || y+2==h ? 2 : yadif->mode;
00137 yadif->filter_line(dst, prev, cur, next, w, y+1<h ? refs : -refs, y ? -refs : refs, parity ^ tff, mode);
00138 } else {
00139 memcpy(&dstpic->data[i][y*dstpic->linesize[i]],
00140 &yadif->cur->data[i][y*refs], w);
00141 }
00142 }
00143 }
00144 #if HAVE_MMX
00145 __asm__ volatile("emms \n\t" : : : "memory");
00146 #endif
00147 }
00148
00149 static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w, int h)
00150 {
00151 AVFilterBufferRef *picref;
00152 int width = FFALIGN(w, 32);
00153 int height= FFALIGN(h+2, 32);
00154 int i;
00155
00156 picref = avfilter_default_get_video_buffer(link, perms, width, height);
00157
00158 picref->video->w = w;
00159 picref->video->h = h;
00160
00161 for (i = 0; i < 3; i++)
00162 picref->data[i] += picref->linesize[i];
00163
00164 return picref;
00165 }
00166
00167 static void return_frame(AVFilterContext *ctx, int is_second)
00168 {
00169 YADIFContext *yadif = ctx->priv;
00170 AVFilterLink *link= ctx->outputs[0];
00171 int tff;
00172
00173 if (yadif->parity == -1) {
00174 tff = yadif->cur->video->interlaced ?
00175 yadif->cur->video->top_field_first : 1;
00176 } else {
00177 tff = yadif->parity^1;
00178 }
00179
00180 if (is_second)
00181 yadif->out = avfilter_get_video_buffer(link, AV_PERM_WRITE | AV_PERM_PRESERVE |
00182 AV_PERM_REUSE, link->w, link->h);
00183
00184 filter(ctx, yadif->out, tff ^ !is_second, tff);
00185
00186 if (is_second) {
00187 if (yadif->next->pts != AV_NOPTS_VALUE &&
00188 yadif->cur->pts != AV_NOPTS_VALUE) {
00189 yadif->out->pts =
00190 (yadif->next->pts&yadif->cur->pts) +
00191 ((yadif->next->pts^yadif->cur->pts)>>1);
00192 } else {
00193 yadif->out->pts = AV_NOPTS_VALUE;
00194 }
00195 avfilter_start_frame(ctx->outputs[0], yadif->out);
00196 }
00197 avfilter_draw_slice(ctx->outputs[0], 0, link->h, 1);
00198 avfilter_end_frame(ctx->outputs[0]);
00199
00200 yadif->frame_pending = (yadif->mode&1) && !is_second;
00201 }
00202
00203 static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
00204 {
00205 AVFilterContext *ctx = link->dst;
00206 YADIFContext *yadif = ctx->priv;
00207
00208 if (yadif->frame_pending)
00209 return_frame(ctx, 1);
00210
00211 if (yadif->prev)
00212 avfilter_unref_buffer(yadif->prev);
00213 yadif->prev = yadif->cur;
00214 yadif->cur = yadif->next;
00215 yadif->next = picref;
00216
00217 if (!yadif->cur)
00218 return;
00219
00220 if (!yadif->prev)
00221 yadif->prev = avfilter_ref_buffer(yadif->cur, AV_PERM_READ);
00222
00223 yadif->out = avfilter_get_video_buffer(ctx->outputs[0], AV_PERM_WRITE | AV_PERM_PRESERVE |
00224 AV_PERM_REUSE, link->w, link->h);
00225
00226 avfilter_copy_buffer_ref_props(yadif->out, yadif->cur);
00227 yadif->out->video->interlaced = 0;
00228 avfilter_start_frame(ctx->outputs[0], yadif->out);
00229 }
00230
00231 static void end_frame(AVFilterLink *link)
00232 {
00233 AVFilterContext *ctx = link->dst;
00234 YADIFContext *yadif = ctx->priv;
00235
00236 if (!yadif->out)
00237 return;
00238
00239 return_frame(ctx, 0);
00240 }
00241
00242 static int request_frame(AVFilterLink *link)
00243 {
00244 AVFilterContext *ctx = link->src;
00245 YADIFContext *yadif = ctx->priv;
00246
00247 if (yadif->frame_pending) {
00248 return_frame(ctx, 1);
00249 return 0;
00250 }
00251
00252 do {
00253 int ret;
00254
00255 if ((ret = avfilter_request_frame(link->src->inputs[0])))
00256 return ret;
00257 } while (!yadif->cur);
00258
00259 return 0;
00260 }
00261
00262 static int poll_frame(AVFilterLink *link)
00263 {
00264 YADIFContext *yadif = link->src->priv;
00265 int ret, val;
00266
00267 if (yadif->frame_pending)
00268 return 1;
00269
00270 val = avfilter_poll_frame(link->src->inputs[0]);
00271
00272 if (val==1 && !yadif->next) {
00273 if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0)
00274 return ret;
00275 val = avfilter_poll_frame(link->src->inputs[0]);
00276 }
00277 assert(yadif->next);
00278
00279 return val * ((yadif->mode&1)+1);
00280 }
00281
00282 static av_cold void uninit(AVFilterContext *ctx)
00283 {
00284 YADIFContext *yadif = ctx->priv;
00285
00286 if (yadif->prev) avfilter_unref_buffer(yadif->prev);
00287 if (yadif->cur ) avfilter_unref_buffer(yadif->cur );
00288 if (yadif->next) avfilter_unref_buffer(yadif->next);
00289 }
00290
00291 static int query_formats(AVFilterContext *ctx)
00292 {
00293 static const enum PixelFormat pix_fmts[] = {
00294 PIX_FMT_YUV420P,
00295 PIX_FMT_GRAY8,
00296 PIX_FMT_NONE
00297 };
00298
00299 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
00300
00301 return 0;
00302 }
00303
00304 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
00305 {
00306 YADIFContext *yadif = ctx->priv;
00307 av_unused int cpu_flags = av_get_cpu_flags();
00308
00309 yadif->mode = 0;
00310 yadif->parity = -1;
00311
00312 if (args) sscanf(args, "%d:%d", &yadif->mode, &yadif->parity);
00313
00314 yadif->filter_line = filter_line_c;
00315 if (HAVE_SSSE3 && cpu_flags & AV_CPU_FLAG_SSSE3)
00316 yadif->filter_line = ff_yadif_filter_line_ssse3;
00317 else if (HAVE_SSE && cpu_flags & AV_CPU_FLAG_SSE2)
00318 yadif->filter_line = ff_yadif_filter_line_sse2;
00319 else if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX)
00320 yadif->filter_line = ff_yadif_filter_line_mmx;
00321
00322 av_log(ctx, AV_LOG_INFO, "mode:%d parity:%d\n", yadif->mode, yadif->parity);
00323
00324 return 0;
00325 }
00326
00327 static void null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir) { }
00328
00329 AVFilter avfilter_vf_yadif = {
00330 .name = "yadif",
00331 .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image"),
00332
00333 .priv_size = sizeof(YADIFContext),
00334 .init = init,
00335 .uninit = uninit,
00336 .query_formats = query_formats,
00337
00338 .inputs = (AVFilterPad[]) {{ .name = "default",
00339 .type = AVMEDIA_TYPE_VIDEO,
00340 .start_frame = start_frame,
00341 .get_video_buffer = get_video_buffer,
00342 .draw_slice = null_draw_slice,
00343 .end_frame = end_frame, },
00344 { .name = NULL}},
00345
00346 .outputs = (AVFilterPad[]) {{ .name = "default",
00347 .type = AVMEDIA_TYPE_VIDEO,
00348 .poll_frame = poll_frame,
00349 .request_frame = request_frame, },
00350 { .name = NULL}},
00351 };