1 /*****************************************************************************
2 * deinterlace.c : deinterlacer plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2011 VLC authors and VideoLAN
7 * Author: Sam Hocevar <sam@zoy.org>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Laurent Aimar <fenrir@videolan.org>
10 * Juha Jeronen <juha.jeronen@jyu.fi>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
41 #include <vlc_filter.h>
43 #include <vlc_mouse.h>
45 #include "deinterlace.h"
49 /*****************************************************************************
51 *****************************************************************************/
53 #define MODE_TEXT N_("Deinterlace mode")
55 #define SOUT_MODE_TEXT N_("Streaming deinterlace mode")
56 #define SOUT_MODE_LONGTEXT N_("Deinterlace method to use for streaming.")
58 #define FILTER_CFG_PREFIX "sout-deinterlace-"
60 /* Tooltips drop linefeeds (at least in the Qt GUI);
61 thus the space before each set of consecutive \n.
63 See phosphor.h for phosphor_chroma_list and phosphor_dimmer_list.
65 #define PHOSPHOR_CHROMA_TEXT N_("Phosphor chroma mode for 4:2:0 input")
66 #define PHOSPHOR_CHROMA_LONGTEXT N_("Choose handling for colours in those "\
67 "output frames that fall across input "\
68 "frame boundaries. \n"\
70 "Latest: take chroma from new (bright) "\
71 "field only. Good for interlaced input, "\
72 "such as videos from a camcorder. \n"\
74 "AltLine: take chroma line 1 from top "\
75 "field, line 2 from bottom field, etc. \n"\
76 "Default, good for NTSC telecined input "\
77 "(anime DVDs, etc.). \n"\
79 "Blend: average input field chromas. "\
80 "May distort the colours of the new "\
81 "(bright) field, too. \n"\
83 "Upconvert: output in 4:2:2 format "\
84 "(independent chroma for each field). "\
85 "Best simulation, but requires more CPU "\
86 "and memory bandwidth.")
88 #define PHOSPHOR_DIMMER_TEXT N_("Phosphor old field dimmer strength")
89 #define PHOSPHOR_DIMMER_LONGTEXT N_("This controls the strength of the "\
90 "darkening filter that simulates CRT TV "\
91 "phosphor light decay for the old field "\
92 "in the Phosphor framerate doubler. "\
96 set_description( N_("Deinterlacing video filter") )
97 set_shortname( N_("Deinterlace" ))
98 set_capability( "video filter2", 0 )
99 set_category( CAT_VIDEO )
100 set_subcategory( SUBCAT_VIDEO_VFILTER )
102 add_string( FILTER_CFG_PREFIX "mode", "blend", SOUT_MODE_TEXT,
103 SOUT_MODE_LONGTEXT, false )
104 change_string_list( mode_list, mode_list_text )
106 add_integer( FILTER_CFG_PREFIX "phosphor-chroma", 2, PHOSPHOR_CHROMA_TEXT,
107 PHOSPHOR_CHROMA_LONGTEXT, true )
108 change_integer_list( phosphor_chroma_list, phosphor_chroma_list_text )
110 add_integer( FILTER_CFG_PREFIX "phosphor-dimmer", 2, PHOSPHOR_DIMMER_TEXT,
111 PHOSPHOR_DIMMER_LONGTEXT, true )
112 change_integer_list( phosphor_dimmer_list, phosphor_dimmer_list_text )
114 add_shortcut( "deinterlace" )
115 set_callbacks( Open, Close )
118 /*****************************************************************************
120 *****************************************************************************/
123 * Available config options for the deinterlacer module.
125 * Note that also algorithm-specific options must be listed here,
126 * and reading logic for them implemented in Open().
128 static const char *const ppsz_filter_options[] = {
129 "mode", "phosphor-chroma", "phosphor-dimmer",
133 /*****************************************************************************
134 * SetFilterMethod: setup the deinterlace method to use.
135 *****************************************************************************/
138 * Setup the deinterlace method to use.
140 * FIXME: extract i_chroma from p_filter automatically?
142 * @param p_filter The filter instance.
143 * @param mode Desired method. See mode_list for available choices.
146 static void SetFilterMethod( filter_t *p_filter, const char *mode, bool pack )
148 filter_sys_t *p_sys = p_filter->p_sys;
153 p_sys->i_mode = DEINTERLACE_BLEND; /* default */
154 p_sys->b_double_rate = false;
155 p_sys->b_half_height = false;
156 p_sys->b_use_frame_history = false;
158 if( !strcmp( mode, "discard" ) )
160 p_sys->i_mode = DEINTERLACE_DISCARD;
161 p_sys->b_half_height = true;
163 else if( !strcmp( mode, "bob" ) || !strcmp( mode, "progressive-scan" ) )
165 p_sys->i_mode = DEINTERLACE_BOB;
166 p_sys->b_double_rate = true;
168 else if( !strcmp( mode, "linear" ) )
170 p_sys->i_mode = DEINTERLACE_LINEAR;
171 p_sys->b_double_rate = true;
173 else if( !strcmp( mode, "mean" ) )
175 p_sys->i_mode = DEINTERLACE_MEAN;
176 p_sys->b_half_height = true;
178 else if( !strcmp( mode, "blend" ) )
183 msg_Err( p_filter, "unknown or incompatible deinterlace mode \"%s\""
184 " for packed format", mode );
187 else if( !strcmp( mode, "yadif" ) )
189 p_sys->i_mode = DEINTERLACE_YADIF;
190 p_sys->b_use_frame_history = true;
192 else if( !strcmp( mode, "yadif2x" ) )
194 p_sys->i_mode = DEINTERLACE_YADIF2X;
195 p_sys->b_double_rate = true;
196 p_sys->b_use_frame_history = true;
198 else if( p_sys->chroma->pixel_size > 1 )
200 msg_Err( p_filter, "unknown or incompatible deinterlace mode \"%s\""
201 " for high depth format", mode );
204 else if( !strcmp( mode, "x" ) )
206 p_sys->i_mode = DEINTERLACE_X;
208 else if( !strcmp( mode, "phosphor" ) )
210 p_sys->i_mode = DEINTERLACE_PHOSPHOR;
211 p_sys->b_double_rate = true;
212 p_sys->b_use_frame_history = true;
214 else if( !strcmp( mode, "ivtc" ) )
216 p_sys->i_mode = DEINTERLACE_IVTC;
217 p_sys->b_use_frame_history = true;
220 msg_Err( p_filter, "unknown deinterlace mode \"%s\"", mode );
222 msg_Dbg( p_filter, "using %s deinterlace method", mode );
226 * Get the output video format of the chosen deinterlace method
227 * for the given input video format.
229 * Note that each algorithm is allowed to specify its output format,
230 * which may (for some input formats) differ from the input format.
232 * @param p_filter The filter instance.
233 * @param[out] p_dst Output video format. The structure must be allocated by ca
234 * @param[in] p_src Input video format.
235 * @see SetFilterMethod()
237 static void GetOutputFormat( filter_t *p_filter,
238 video_format_t *p_dst, const video_format_t *p_src )
240 filter_sys_t *p_sys = p_filter->p_sys;
243 if( p_sys->b_half_height )
245 p_dst->i_height /= 2;
246 p_dst->i_visible_height /= 2;
247 p_dst->i_y_offset /= 2;
248 p_dst->i_sar_den *= 2;
251 if( p_sys->b_double_rate )
253 p_dst->i_frame_rate *= 2;
256 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR &&
257 2 * p_sys->chroma->p[1].h.num == p_sys->chroma->p[1].h.den &&
258 2 * p_sys->chroma->p[2].h.num == p_sys->chroma->p[2].h.den &&
259 p_sys->phosphor.i_chroma_for_420 == PC_UPCONVERT )
261 p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_J420 ? VLC_CODEC_J422 :
266 p_dst->i_chroma = p_src->i_chroma;
271 /*****************************************************************************
272 * video filter2 functions
273 *****************************************************************************/
275 #define DEINTERLACE_DST_SIZE 3
277 /* This is the filter function. See Open(). */
278 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
280 filter_sys_t *p_sys = p_filter->p_sys;
281 picture_t *p_dst[DEINTERLACE_DST_SIZE];
283 /* Request output picture */
284 p_dst[0] = filter_NewPicture( p_filter );
285 if( p_dst[0] == NULL )
287 picture_Release( p_pic );
290 picture_CopyProperties( p_dst[0], p_pic );
292 /* Any unused p_dst pointers must be NULL, because they are used to
293 check how many output frames we have. */
294 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
297 /* Update the input frame history, if the currently active algorithm
299 if( p_sys->b_use_frame_history )
301 /* Duplicate the picture
302 * TODO when the vout rework is finished, picture_Hold() might be enough
303 * but becarefull, the pitches must match */
304 picture_t *p_dup = picture_NewFromFormat( &p_pic->format );
306 picture_Copy( p_dup, p_pic );
308 /* Slide the history */
309 if( p_sys->pp_history[0] )
310 picture_Release( p_sys->pp_history[0] );
311 for( int i = 1; i < HISTORY_SIZE; i++ )
312 p_sys->pp_history[i-1] = p_sys->pp_history[i];
313 p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
316 /* Slide the metadata history. */
317 for( int i = 1; i < METADATA_SIZE; i++ )
319 p_sys->meta.pi_date[i-1] = p_sys->meta.pi_date[i];
320 p_sys->meta.pi_nb_fields[i-1] = p_sys->meta.pi_nb_fields[i];
321 p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i];
323 /* The last element corresponds to the current input frame. */
324 p_sys->meta.pi_date[METADATA_SIZE-1] = p_pic->date;
325 p_sys->meta.pi_nb_fields[METADATA_SIZE-1] = p_pic->i_nb_fields;
326 p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first;
328 /* Remember the frame offset that we should use for this frame.
329 The value in p_sys will be updated to reflect the correct value
330 for the *next* frame when we call the renderer. */
331 int i_frame_offset = p_sys->i_frame_offset;
332 int i_meta_idx = (METADATA_SIZE-1) - i_frame_offset;
334 /* These correspond to the current *outgoing* frame. */
335 bool b_top_field_first;
337 if( i_frame_offset != CUSTOM_PTS )
339 /* Pick the correct values from the history. */
340 b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx];
341 i_nb_fields = p_sys->meta.pi_nb_fields[i_meta_idx];
345 /* Framerate doublers must not request CUSTOM_PTS, as they need the
346 original field timings, and need Deinterlace() to allocate the
347 correct number of output frames. */
348 assert( !p_sys->b_double_rate );
350 /* NOTE: i_nb_fields is only used for framerate doublers, so it is
351 unused in this case. b_top_field_first is only passed to the
352 algorithm. We assume that algorithms that request CUSTOM_PTS
353 will, if necessary, extract the TFF/BFF information themselves.
355 b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
357 i_nb_fields = p_pic->i_nb_fields; /* unused */
360 /* For framerate doublers, determine field duration and allocate
362 mtime_t i_field_dur = 0;
363 int i_double_rate_alloc_end = 0; /* One past last for allocated output
364 frames in p_dst[]. Used only for
365 framerate doublers. Will be inited
366 below. Declared here because the
367 PTS logic needs the result. */
368 if( p_sys->b_double_rate )
370 /* Calculate one field duration. */
372 int iend = METADATA_SIZE-1;
373 /* Find oldest valid logged date.
374 The current input frame doesn't count. */
375 for( ; i < iend; i++ )
376 if( p_sys->meta.pi_date[i] > VLC_TS_INVALID )
380 /* Count how many fields the valid history entries
381 (except the new frame) represent. */
382 int i_fields_total = 0;
383 for( int j = i ; j < iend; j++ )
384 i_fields_total += p_sys->meta.pi_nb_fields[j];
385 /* One field took this long. */
386 i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total;
388 /* Note that we default to field duration 0 if it could not be
389 determined. This behaves the same as the old code - leaving the
390 extra output frame dates the same as p_pic->date if the last cached
394 i_double_rate_alloc_end = i_nb_fields;
395 if( i_nb_fields > DEINTERLACE_DST_SIZE )
397 /* Note that the effective buffer size depends also on the constant
398 private_picture in vout_wrapper.c, since that determines the
399 maximum number of output pictures filter_NewPicture() will
400 successfully allocate for one input frame.
402 msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
403 "fields = %d, buffer size = %d. Dropping the "\
405 i_nb_fields, DEINTERLACE_DST_SIZE );
406 i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
409 /* Allocate output frames. */
410 for( int i = 1; i < i_double_rate_alloc_end ; ++i )
413 p_dst[i] = filter_NewPicture( p_filter );
416 picture_CopyProperties( p_dst[i], p_pic );
420 msg_Err( p_filter, "Framerate doubler: could not allocate "\
421 "output frame %d", i+1 );
422 i_double_rate_alloc_end = i; /* Inform the PTS logic about the
423 correct end position. */
424 break; /* If this happens, the rest of the allocations
425 aren't likely to work, either... */
428 /* Now we have allocated *up to* the correct number of frames;
429 normally, exactly the correct number. Upon alloc failure,
430 we may have succeeded in allocating *some* output frames,
431 but fewer than were desired. In such a case, as many will
432 be rendered as were successfully allocated.
434 Note that now p_dst[i] != NULL
435 for 0 <= i < i_double_rate_alloc_end. */
437 assert( p_sys->b_double_rate || p_dst[1] == NULL );
438 assert( i_nb_fields > 2 || p_dst[2] == NULL );
441 switch( p_sys->i_mode )
443 case DEINTERLACE_DISCARD:
444 RenderDiscard( p_dst[0], p_pic, 0 );
447 case DEINTERLACE_BOB:
448 RenderBob( p_dst[0], p_pic, !b_top_field_first );
450 RenderBob( p_dst[1], p_pic, b_top_field_first );
452 RenderBob( p_dst[2], p_pic, !b_top_field_first );
455 case DEINTERLACE_LINEAR:
456 RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
458 RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
460 RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
463 case DEINTERLACE_MEAN:
464 RenderMean( p_filter, p_dst[0], p_pic );
467 case DEINTERLACE_BLEND:
468 RenderBlend( p_filter, p_dst[0], p_pic );
472 RenderX( p_dst[0], p_pic );
475 case DEINTERLACE_YADIF:
476 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
480 case DEINTERLACE_YADIF2X:
481 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
484 RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
486 RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
489 case DEINTERLACE_PHOSPHOR:
490 if( RenderPhosphor( p_filter, p_dst[0], 0,
491 !b_top_field_first ) )
494 RenderPhosphor( p_filter, p_dst[1], 1,
497 RenderPhosphor( p_filter, p_dst[2], 2,
498 !b_top_field_first );
501 case DEINTERLACE_IVTC:
502 /* Note: RenderIVTC will automatically drop the duplicate frames
503 produced by IVTC. This is part of normal operation. */
504 if( RenderIVTC( p_filter, p_dst[0] ) )
509 /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
511 assert( i_frame_offset <= METADATA_SIZE || i_frame_offset == CUSTOM_PTS );
512 if( i_frame_offset != CUSTOM_PTS )
514 mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];
516 /* Note: in the usual case (i_frame_offset = 0 and
517 b_double_rate = false), this effectively does nothing.
518 This is needed to correct the timestamp
519 when i_frame_offset > 0. */
520 p_dst[0]->date = i_base_pts;
522 if( p_sys->b_double_rate )
524 /* Processing all actually allocated output frames. */
525 for( int i = 1; i < i_double_rate_alloc_end; ++i )
527 /* XXX it's not really good especially for the first picture, but
528 * I don't think that delaying by one frame is worth it */
529 if( i_base_pts > VLC_TS_INVALID )
530 p_dst[i]->date = i_base_pts + i * i_field_dur;
532 p_dst[i]->date = VLC_TS_INVALID;
537 for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
541 p_dst[i]->b_progressive = true;
542 p_dst[i]->i_nb_fields = 2;
546 picture_Release( p_pic );
550 picture_Release( p_dst[0] );
551 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
554 picture_Release( p_dst[i] );
556 picture_Release( p_pic );
560 /*****************************************************************************
562 *****************************************************************************/
564 void Flush( filter_t *p_filter )
566 filter_sys_t *p_sys = p_filter->p_sys;
568 for( int i = 0; i < METADATA_SIZE; i++ )
570 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
571 p_sys->meta.pi_nb_fields[i] = 2;
572 p_sys->meta.pb_top_field_first[i] = true;
574 p_sys->i_frame_offset = 0; /* reset to default value (first frame after
575 flush cannot have offset) */
576 for( int i = 0; i < HISTORY_SIZE; i++ )
578 if( p_sys->pp_history[i] )
579 picture_Release( p_sys->pp_history[i] );
580 p_sys->pp_history[i] = NULL;
582 IVTCClearState( p_filter );
585 /*****************************************************************************
586 * Mouse event callback
587 *****************************************************************************/
589 int Mouse( filter_t *p_filter,
590 vlc_mouse_t *p_mouse,
591 const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
595 if( p_filter->p_sys->b_half_height )
601 /*****************************************************************************
603 *****************************************************************************/
605 int Open( vlc_object_t *p_this )
607 filter_t *p_filter = (filter_t*)p_this;
610 const vlc_fourcc_t fourcc = p_filter->fmt_in.video.i_chroma;
611 const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription( fourcc );
612 if( chroma == NULL || chroma->pixel_size > 2 )
615 msg_Err( p_filter, "unsupported chroma %4.4s", (char*)&fourcc );
619 unsigned pixel_size = chroma->pixel_size;
621 if( chroma->plane_count != 3 )
638 assert( vlc_fourcc_IsYUV( fourcc ) );
641 p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
645 p_sys->chroma = chroma;
647 config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
649 char *psz_mode = var_InheritString( p_filter, FILTER_CFG_PREFIX "mode" );
650 SetFilterMethod( p_filter, psz_mode, packed );
653 for( int i = 0; i < METADATA_SIZE; i++ )
655 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
656 p_sys->meta.pi_nb_fields[i] = 2;
657 p_sys->meta.pb_top_field_first[i] = true;
659 p_sys->i_frame_offset = 0; /* start with default value (first-ever frame
660 cannot have offset) */
661 for( int i = 0; i < HISTORY_SIZE; i++ )
662 p_sys->pp_history[i] = NULL;
664 IVTCClearState( p_filter );
666 #if defined(CAN_COMPILE_C_ALTIVEC)
667 if( pixel_size == 1 && vlc_CPU_ALTIVEC() )
668 p_sys->pf_merge = MergeAltivec;
671 #if defined(CAN_COMPILE_SSE2)
674 p_sys->pf_merge = pixel_size == 1 ? Merge8BitSSE2 : Merge16BitSSE2;
675 p_sys->pf_end_merge = EndMMX;
679 #if defined(CAN_COMPILE_MMXEXT)
680 if( pixel_size == 1 && vlc_CPU_MMXEXT() )
682 p_sys->pf_merge = MergeMMXEXT;
683 p_sys->pf_end_merge = EndMMX;
687 #if defined(CAN_COMPILE_3DNOW)
688 if( pixel_size == 1 && vlc_CPU_3dNOW() )
690 p_sys->pf_merge = Merge3DNow;
691 p_sys->pf_end_merge = End3DNow;
695 #if defined(CAN_COMPILE_ARM)
696 if( vlc_CPU_ARM_NEON() )
697 p_sys->pf_merge = pixel_size == 1 ? merge8_arm_neon : merge16_arm_neon;
699 if( vlc_CPU_ARMv6() )
700 p_sys->pf_merge = pixel_size == 1 ? merge8_armv6 : merge16_armv6;
704 p_sys->pf_merge = pixel_size == 1 ? Merge8BitGeneric : Merge16BitGeneric;
705 #if defined(__i386__) || defined(__x86_64__)
706 p_sys->pf_end_merge = NULL;
711 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR )
713 int i_c420 = var_GetInteger( p_filter,
714 FILTER_CFG_PREFIX "phosphor-chroma" );
715 if( i_c420 != PC_LATEST && i_c420 != PC_ALTLINE &&
716 i_c420 != PC_BLEND && i_c420 != PC_UPCONVERT )
718 msg_Dbg( p_filter, "Phosphor 4:2:0 input chroma mode not set"\
719 "or out of range (valid: 1, 2, 3 or 4), "\
723 msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d",
725 /* This maps directly to the phosphor_chroma_t enum. */
726 p_sys->phosphor.i_chroma_for_420 = i_c420;
728 int i_dimmer = var_GetInteger( p_filter,
729 FILTER_CFG_PREFIX "phosphor-dimmer" );
730 if( i_dimmer < 1 || i_dimmer > 4 )
732 msg_Dbg( p_filter, "Phosphor dimmer strength not set "\
733 "or out of range (valid: 1, 2, 3 or 4), "\
735 i_dimmer = 2; /* low */
737 msg_Dbg( p_filter, "using Phosphor dimmer strength %d", i_dimmer );
738 /* The internal value ranges from 0 to 3. */
739 p_sys->phosphor.i_dimmer_strength = i_dimmer - 1;
743 p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE;
744 p_sys->phosphor.i_dimmer_strength = 1;
749 GetOutputFormat( p_filter, &fmt, &p_filter->fmt_in.video );
750 if( !p_filter->b_allow_fmt_out_change &&
751 ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma ||
752 fmt.i_height != p_filter->fmt_in.video.i_height ) )
754 Close( VLC_OBJECT(p_filter) );
757 p_filter->fmt_out.video = fmt;
758 p_filter->fmt_out.i_codec = fmt.i_chroma;
759 p_filter->pf_video_filter = Deinterlace;
760 p_filter->pf_video_flush = Flush;
761 p_filter->pf_video_mouse = Mouse;
763 msg_Dbg( p_filter, "deinterlacing" );
768 /*****************************************************************************
769 * Close: clean up the filter
770 *****************************************************************************/
772 void Close( vlc_object_t *p_this )
774 filter_t *p_filter = (filter_t*)p_this;
777 free( p_filter->p_sys );