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 psz_method Desired method. See mode_list for available choices.
146 static void SetFilterMethod( filter_t *p_filter, const char *psz_method )
148 filter_sys_t *p_sys = p_filter->p_sys;
153 p_sys->b_double_rate = false;
154 p_sys->b_half_height = false;
155 p_sys->b_use_frame_history = false;
157 if( !strcmp( psz_method, "mean" ) )
159 p_sys->i_mode = DEINTERLACE_MEAN;
160 p_sys->b_half_height = true;
162 else if( !strcmp( psz_method, "bob" )
163 || !strcmp( psz_method, "progressive-scan" ) )
165 p_sys->i_mode = DEINTERLACE_BOB;
166 p_sys->b_double_rate = true;
168 else if( !strcmp( psz_method, "linear" ) )
170 p_sys->i_mode = DEINTERLACE_LINEAR;
171 p_sys->b_double_rate = true;
173 else if( !strcmp( psz_method, "x" ) && p_sys->chroma->pixel_size == 1 )
175 p_sys->i_mode = DEINTERLACE_X;
177 else if( !strcmp( psz_method, "yadif" ) )
179 p_sys->i_mode = DEINTERLACE_YADIF;
180 p_sys->b_use_frame_history = true;
182 else if( !strcmp( psz_method, "yadif2x" ) )
184 p_sys->i_mode = DEINTERLACE_YADIF2X;
185 p_sys->b_double_rate = true;
186 p_sys->b_use_frame_history = true;
188 else if( !strcmp( psz_method, "phosphor" ) && p_sys->chroma->pixel_size == 1 )
190 p_sys->i_mode = DEINTERLACE_PHOSPHOR;
191 p_sys->b_double_rate = true;
192 p_sys->b_use_frame_history = true;
194 else if( !strcmp( psz_method, "ivtc" ) && p_sys->chroma->pixel_size == 1 )
196 p_sys->i_mode = DEINTERLACE_IVTC;
197 p_sys->b_use_frame_history = true;
199 else if( !strcmp( psz_method, "discard" ) )
201 p_sys->i_mode = DEINTERLACE_DISCARD;
202 p_sys->b_half_height = true;
206 if( strcmp( psz_method, "blend" ) )
208 "no valid/compatible deinterlace mode provided, using \"blend\"" );
210 p_sys->i_mode = DEINTERLACE_BLEND;
213 p_sys->i_frame_offset = 0; /* reset to default when method changes */
215 msg_Dbg( p_filter, "using %s deinterlace method", psz_method );
219 * Get the output video format of the chosen deinterlace method
220 * for the given input video format.
222 * Note that each algorithm is allowed to specify its output format,
223 * which may (for some input formats) differ from the input format.
225 * @param p_filter The filter instance.
226 * @param[out] p_dst Output video format. The structure must be allocated by ca
227 * @param[in] p_src Input video format.
228 * @see SetFilterMethod()
230 static void GetOutputFormat( filter_t *p_filter,
231 video_format_t *p_dst, const video_format_t *p_src )
233 filter_sys_t *p_sys = p_filter->p_sys;
236 if( p_sys->b_half_height )
238 p_dst->i_height /= 2;
239 p_dst->i_visible_height /= 2;
240 p_dst->i_y_offset /= 2;
241 p_dst->i_sar_den *= 2;
244 if( p_sys->b_double_rate )
246 p_dst->i_frame_rate *= 2;
249 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR &&
250 2 * p_sys->chroma->p[1].h.num == p_sys->chroma->p[1].h.den &&
251 2 * p_sys->chroma->p[2].h.num == p_sys->chroma->p[2].h.den &&
252 p_sys->phosphor.i_chroma_for_420 == PC_UPCONVERT )
254 p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_J420 ? VLC_CODEC_J422 :
259 p_dst->i_chroma = p_src->i_chroma;
264 /*****************************************************************************
265 * video filter2 functions
266 *****************************************************************************/
268 #define DEINTERLACE_DST_SIZE 3
270 /* This is the filter function. See Open(). */
271 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
273 filter_sys_t *p_sys = p_filter->p_sys;
274 picture_t *p_dst[DEINTERLACE_DST_SIZE];
276 /* Request output picture */
277 p_dst[0] = filter_NewPicture( p_filter );
278 if( p_dst[0] == NULL )
280 picture_Release( p_pic );
283 picture_CopyProperties( p_dst[0], p_pic );
285 /* Any unused p_dst pointers must be NULL, because they are used to
286 check how many output frames we have. */
287 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
290 /* Update the input frame history, if the currently active algorithm
292 if( p_sys->b_use_frame_history )
294 /* Duplicate the picture
295 * TODO when the vout rework is finished, picture_Hold() might be enough
296 * but becarefull, the pitches must match */
297 picture_t *p_dup = picture_NewFromFormat( &p_pic->format );
299 picture_Copy( p_dup, p_pic );
301 /* Slide the history */
302 if( p_sys->pp_history[0] )
303 picture_Release( p_sys->pp_history[0] );
304 for( int i = 1; i < HISTORY_SIZE; i++ )
305 p_sys->pp_history[i-1] = p_sys->pp_history[i];
306 p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
309 /* Slide the metadata history. */
310 for( int i = 1; i < METADATA_SIZE; i++ )
312 p_sys->meta.pi_date[i-1] = p_sys->meta.pi_date[i];
313 p_sys->meta.pi_nb_fields[i-1] = p_sys->meta.pi_nb_fields[i];
314 p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i];
316 /* The last element corresponds to the current input frame. */
317 p_sys->meta.pi_date[METADATA_SIZE-1] = p_pic->date;
318 p_sys->meta.pi_nb_fields[METADATA_SIZE-1] = p_pic->i_nb_fields;
319 p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first;
321 /* Remember the frame offset that we should use for this frame.
322 The value in p_sys will be updated to reflect the correct value
323 for the *next* frame when we call the renderer. */
324 int i_frame_offset = p_sys->i_frame_offset;
325 int i_meta_idx = (METADATA_SIZE-1) - i_frame_offset;
327 /* These correspond to the current *outgoing* frame. */
328 bool b_top_field_first;
330 if( i_frame_offset != CUSTOM_PTS )
332 /* Pick the correct values from the history. */
333 b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx];
334 i_nb_fields = p_sys->meta.pi_nb_fields[i_meta_idx];
338 /* Framerate doublers must not request CUSTOM_PTS, as they need the
339 original field timings, and need Deinterlace() to allocate the
340 correct number of output frames. */
341 assert( !p_sys->b_double_rate );
343 /* NOTE: i_nb_fields is only used for framerate doublers, so it is
344 unused in this case. b_top_field_first is only passed to the
345 algorithm. We assume that algorithms that request CUSTOM_PTS
346 will, if necessary, extract the TFF/BFF information themselves.
348 b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
350 i_nb_fields = p_pic->i_nb_fields; /* unused */
353 /* For framerate doublers, determine field duration and allocate
355 mtime_t i_field_dur = 0;
356 int i_double_rate_alloc_end = 0; /* One past last for allocated output
357 frames in p_dst[]. Used only for
358 framerate doublers. Will be inited
359 below. Declared here because the
360 PTS logic needs the result. */
361 if( p_sys->b_double_rate )
363 /* Calculate one field duration. */
365 int iend = METADATA_SIZE-1;
366 /* Find oldest valid logged date.
367 The current input frame doesn't count. */
368 for( ; i < iend; i++ )
369 if( p_sys->meta.pi_date[i] > VLC_TS_INVALID )
373 /* Count how many fields the valid history entries
374 (except the new frame) represent. */
375 int i_fields_total = 0;
376 for( int j = i ; j < iend; j++ )
377 i_fields_total += p_sys->meta.pi_nb_fields[j];
378 /* One field took this long. */
379 i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total;
381 /* Note that we default to field duration 0 if it could not be
382 determined. This behaves the same as the old code - leaving the
383 extra output frame dates the same as p_pic->date if the last cached
387 i_double_rate_alloc_end = i_nb_fields;
388 if( i_nb_fields > DEINTERLACE_DST_SIZE )
390 /* Note that the effective buffer size depends also on the constant
391 private_picture in vout_wrapper.c, since that determines the
392 maximum number of output pictures filter_NewPicture() will
393 successfully allocate for one input frame.
395 msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
396 "fields = %d, buffer size = %d. Dropping the "\
398 i_nb_fields, DEINTERLACE_DST_SIZE );
399 i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
402 /* Allocate output frames. */
403 for( int i = 1; i < i_double_rate_alloc_end ; ++i )
406 p_dst[i] = filter_NewPicture( p_filter );
409 picture_CopyProperties( p_dst[i], p_pic );
413 msg_Err( p_filter, "Framerate doubler: could not allocate "\
414 "output frame %d", i+1 );
415 i_double_rate_alloc_end = i; /* Inform the PTS logic about the
416 correct end position. */
417 break; /* If this happens, the rest of the allocations
418 aren't likely to work, either... */
421 /* Now we have allocated *up to* the correct number of frames;
422 normally, exactly the correct number. Upon alloc failure,
423 we may have succeeded in allocating *some* output frames,
424 but fewer than were desired. In such a case, as many will
425 be rendered as were successfully allocated.
427 Note that now p_dst[i] != NULL
428 for 0 <= i < i_double_rate_alloc_end. */
430 assert( p_sys->b_double_rate || p_dst[1] == NULL );
431 assert( i_nb_fields > 2 || p_dst[2] == NULL );
434 switch( p_sys->i_mode )
436 case DEINTERLACE_DISCARD:
437 RenderDiscard( p_dst[0], p_pic, 0 );
440 case DEINTERLACE_BOB:
441 RenderBob( p_dst[0], p_pic, !b_top_field_first );
443 RenderBob( p_dst[1], p_pic, b_top_field_first );
445 RenderBob( p_dst[2], p_pic, !b_top_field_first );
448 case DEINTERLACE_LINEAR:
449 RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
451 RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
453 RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
456 case DEINTERLACE_MEAN:
457 RenderMean( p_filter, p_dst[0], p_pic );
460 case DEINTERLACE_BLEND:
461 RenderBlend( p_filter, p_dst[0], p_pic );
465 RenderX( p_dst[0], p_pic );
468 case DEINTERLACE_YADIF:
469 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
473 case DEINTERLACE_YADIF2X:
474 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
477 RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
479 RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
482 case DEINTERLACE_PHOSPHOR:
483 if( RenderPhosphor( p_filter, p_dst[0], 0,
484 !b_top_field_first ) )
487 RenderPhosphor( p_filter, p_dst[1], 1,
490 RenderPhosphor( p_filter, p_dst[2], 2,
491 !b_top_field_first );
494 case DEINTERLACE_IVTC:
495 /* Note: RenderIVTC will automatically drop the duplicate frames
496 produced by IVTC. This is part of normal operation. */
497 if( RenderIVTC( p_filter, p_dst[0] ) )
502 /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
504 assert( i_frame_offset <= METADATA_SIZE || i_frame_offset == CUSTOM_PTS );
505 if( i_frame_offset != CUSTOM_PTS )
507 mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];
509 /* Note: in the usual case (i_frame_offset = 0 and
510 b_double_rate = false), this effectively does nothing.
511 This is needed to correct the timestamp
512 when i_frame_offset > 0. */
513 p_dst[0]->date = i_base_pts;
515 if( p_sys->b_double_rate )
517 /* Processing all actually allocated output frames. */
518 for( int i = 1; i < i_double_rate_alloc_end; ++i )
520 /* XXX it's not really good especially for the first picture, but
521 * I don't think that delaying by one frame is worth it */
522 if( i_base_pts > VLC_TS_INVALID )
523 p_dst[i]->date = i_base_pts + i * i_field_dur;
525 p_dst[i]->date = VLC_TS_INVALID;
530 for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
534 p_dst[i]->b_progressive = true;
535 p_dst[i]->i_nb_fields = 2;
539 picture_Release( p_pic );
543 picture_Release( p_dst[0] );
544 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
547 picture_Release( p_dst[i] );
549 picture_Release( p_pic );
553 /*****************************************************************************
555 *****************************************************************************/
557 void Flush( filter_t *p_filter )
559 filter_sys_t *p_sys = p_filter->p_sys;
561 for( int i = 0; i < METADATA_SIZE; i++ )
563 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
564 p_sys->meta.pi_nb_fields[i] = 2;
565 p_sys->meta.pb_top_field_first[i] = true;
567 p_sys->i_frame_offset = 0; /* reset to default value (first frame after
568 flush cannot have offset) */
569 for( int i = 0; i < HISTORY_SIZE; i++ )
571 if( p_sys->pp_history[i] )
572 picture_Release( p_sys->pp_history[i] );
573 p_sys->pp_history[i] = NULL;
575 IVTCClearState( p_filter );
578 /*****************************************************************************
579 * Mouse event callback
580 *****************************************************************************/
582 int Mouse( filter_t *p_filter,
583 vlc_mouse_t *p_mouse,
584 const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
588 if( p_filter->p_sys->b_half_height )
594 /*****************************************************************************
596 *****************************************************************************/
598 int Open( vlc_object_t *p_this )
600 filter_t *p_filter = (filter_t*)p_this;
603 const vlc_fourcc_t fourcc = p_filter->fmt_in.video.i_chroma;
604 const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription( fourcc );
605 if( !vlc_fourcc_IsYUV( fourcc ) ||
606 !chroma || chroma->plane_count != 3 || chroma->pixel_size > 2 )
608 msg_Err( p_filter, "Unsupported chroma (%4.4s)", (char*)&fourcc );
613 p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
617 p_sys->chroma = chroma;
619 config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
621 char *psz_mode = var_InheritString( p_filter, FILTER_CFG_PREFIX "mode" );
622 SetFilterMethod( p_filter, psz_mode );
625 for( int i = 0; i < METADATA_SIZE; i++ )
627 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
628 p_sys->meta.pi_nb_fields[i] = 2;
629 p_sys->meta.pb_top_field_first[i] = true;
631 p_sys->i_frame_offset = 0; /* start with default value (first-ever frame
632 cannot have offset) */
633 for( int i = 0; i < HISTORY_SIZE; i++ )
634 p_sys->pp_history[i] = NULL;
636 IVTCClearState( p_filter );
638 #if defined(CAN_COMPILE_C_ALTIVEC)
639 if( chroma->pixel_size == 1 && vlc_CPU_ALTIVEC() )
640 p_sys->pf_merge = MergeAltivec;
643 #if defined(CAN_COMPILE_SSE2)
646 p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitSSE2 : Merge16BitSSE2;
647 p_sys->pf_end_merge = EndMMX;
651 #if defined(CAN_COMPILE_MMXEXT)
652 if( chroma->pixel_size == 1 && vlc_CPU_MMXEXT() )
654 p_sys->pf_merge = MergeMMXEXT;
655 p_sys->pf_end_merge = EndMMX;
659 #if defined(CAN_COMPILE_3DNOW)
660 if( chroma->pixel_size == 1 && vlc_CPU_3dNOW() )
662 p_sys->pf_merge = Merge3DNow;
663 p_sys->pf_end_merge = End3DNow;
667 #if defined(CAN_COMPILE_ARM)
668 if( vlc_CPU_ARM_NEON() )
670 (chroma->pixel_size == 1) ? merge8_arm_neon : merge16_arm_neon;
672 if( vlc_CPU_ARMv6() )
674 (chroma->pixel_size == 1) ? merge8_armv6 : merge16_armv6;
678 p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitGeneric : Merge16BitGeneric;
679 #if defined(__i386__) || defined(__x86_64__)
680 p_sys->pf_end_merge = NULL;
685 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR )
687 int i_c420 = var_GetInteger( p_filter,
688 FILTER_CFG_PREFIX "phosphor-chroma" );
689 if( i_c420 != PC_LATEST && i_c420 != PC_ALTLINE &&
690 i_c420 != PC_BLEND && i_c420 != PC_UPCONVERT )
692 msg_Dbg( p_filter, "Phosphor 4:2:0 input chroma mode not set"\
693 "or out of range (valid: 1, 2, 3 or 4), "\
697 msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d",
699 /* This maps directly to the phosphor_chroma_t enum. */
700 p_sys->phosphor.i_chroma_for_420 = i_c420;
702 int i_dimmer = var_GetInteger( p_filter,
703 FILTER_CFG_PREFIX "phosphor-dimmer" );
704 if( i_dimmer < 1 || i_dimmer > 4 )
706 msg_Dbg( p_filter, "Phosphor dimmer strength not set "\
707 "or out of range (valid: 1, 2, 3 or 4), "\
709 i_dimmer = 2; /* low */
711 msg_Dbg( p_filter, "using Phosphor dimmer strength %d", i_dimmer );
712 /* The internal value ranges from 0 to 3. */
713 p_sys->phosphor.i_dimmer_strength = i_dimmer - 1;
717 p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE;
718 p_sys->phosphor.i_dimmer_strength = 1;
723 GetOutputFormat( p_filter, &fmt, &p_filter->fmt_in.video );
724 if( !p_filter->b_allow_fmt_out_change &&
725 ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma ||
726 fmt.i_height != p_filter->fmt_in.video.i_height ) )
728 Close( VLC_OBJECT(p_filter) );
731 p_filter->fmt_out.video = fmt;
732 p_filter->fmt_out.i_codec = fmt.i_chroma;
733 p_filter->pf_video_filter = Deinterlace;
734 p_filter->pf_video_flush = Flush;
735 p_filter->pf_video_mouse = Mouse;
737 msg_Dbg( p_filter, "deinterlacing" );
742 /*****************************************************************************
743 * Close: clean up the filter
744 *****************************************************************************/
746 void Close( vlc_object_t *p_this )
748 filter_t *p_filter = (filter_t*)p_this;
751 free( p_filter->p_sys );