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")
54 #define MODE_LONGTEXT N_("Deinterlace method to use for local playback.")
56 #define SOUT_MODE_TEXT N_("Streaming deinterlace mode")
57 #define SOUT_MODE_LONGTEXT N_("Deinterlace method to use for streaming.")
59 #define FILTER_CFG_PREFIX "sout-deinterlace-"
61 /* Tooltips drop linefeeds (at least in the Qt GUI);
62 thus the space before each set of consecutive \n.
64 See phosphor.h for phosphor_chroma_list and phosphor_dimmer_list.
66 #define PHOSPHOR_CHROMA_TEXT N_("Phosphor chroma mode for 4:2:0 input")
67 #define PHOSPHOR_CHROMA_LONGTEXT N_("Choose handling for colours in those "\
68 "output frames that fall across input "\
69 "frame boundaries. \n"\
71 "Latest: take chroma from new (bright) "\
72 "field only. Good for interlaced input, "\
73 "such as videos from a camcorder. \n"\
75 "AltLine: take chroma line 1 from top "\
76 "field, line 2 from bottom field, etc. \n"\
77 "Default, good for NTSC telecined input "\
78 "(anime DVDs, etc.). \n"\
80 "Blend: average input field chromas. "\
81 "May distort the colours of the new "\
82 "(bright) field, too. \n"\
84 "Upconvert: output in 4:2:2 format "\
85 "(independent chroma for each field). "\
86 "Best simulation, but requires more CPU "\
87 "and memory bandwidth.")
89 #define PHOSPHOR_DIMMER_TEXT N_("Phosphor old field dimmer strength")
90 #define PHOSPHOR_DIMMER_LONGTEXT N_("This controls the strength of the "\
91 "darkening filter that simulates CRT TV "\
92 "phosphor light decay for the old field "\
93 "in the Phosphor framerate doubler. "\
97 set_description( N_("Deinterlacing video filter") )
98 set_shortname( N_("Deinterlace" ))
99 set_capability( "video filter2", 0 )
100 set_category( CAT_VIDEO )
101 set_subcategory( SUBCAT_VIDEO_VFILTER )
103 add_string( FILTER_CFG_PREFIX "mode", "blend", SOUT_MODE_TEXT,
104 SOUT_MODE_LONGTEXT, false )
105 change_string_list( mode_list, mode_list_text )
107 add_integer( FILTER_CFG_PREFIX "phosphor-chroma", 2, PHOSPHOR_CHROMA_TEXT,
108 PHOSPHOR_CHROMA_LONGTEXT, true )
109 change_integer_list( phosphor_chroma_list, phosphor_chroma_list_text )
111 add_integer( FILTER_CFG_PREFIX "phosphor-dimmer", 2, PHOSPHOR_DIMMER_TEXT,
112 PHOSPHOR_DIMMER_LONGTEXT, true )
113 change_integer_list( phosphor_dimmer_list, phosphor_dimmer_list_text )
115 add_shortcut( "deinterlace" )
116 set_callbacks( Open, Close )
119 /*****************************************************************************
121 *****************************************************************************/
124 * Available config options for the deinterlacer module.
126 * Note that also algorithm-specific options must be listed here,
127 * and reading logic for them implemented in Open().
129 static const char *const ppsz_filter_options[] = {
130 "mode", "phosphor-chroma", "phosphor-dimmer",
134 /*****************************************************************************
135 * SetFilterMethod: setup the deinterlace method to use.
136 *****************************************************************************/
138 void SetFilterMethod( filter_t *p_filter, const char *psz_method )
140 filter_sys_t *p_sys = p_filter->p_sys;
145 if( !strcmp( psz_method, "mean" ) )
147 p_sys->i_mode = DEINTERLACE_MEAN;
148 p_sys->b_double_rate = false;
149 p_sys->b_half_height = true;
150 p_sys->b_use_frame_history = false;
152 else if( !strcmp( psz_method, "bob" )
153 || !strcmp( psz_method, "progressive-scan" ) )
155 p_sys->i_mode = DEINTERLACE_BOB;
156 p_sys->b_double_rate = true;
157 p_sys->b_half_height = false;
158 p_sys->b_use_frame_history = false;
160 else if( !strcmp( psz_method, "linear" ) )
162 p_sys->i_mode = DEINTERLACE_LINEAR;
163 p_sys->b_double_rate = true;
164 p_sys->b_half_height = false;
165 p_sys->b_use_frame_history = false;
167 else if( !strcmp( psz_method, "x" ) && p_sys->chroma->pixel_size == 1 )
169 p_sys->i_mode = DEINTERLACE_X;
170 p_sys->b_double_rate = false;
171 p_sys->b_half_height = false;
172 p_sys->b_use_frame_history = false;
174 else if( !strcmp( psz_method, "yadif" ) )
176 p_sys->i_mode = DEINTERLACE_YADIF;
177 p_sys->b_double_rate = false;
178 p_sys->b_half_height = false;
179 p_sys->b_use_frame_history = true;
181 else if( !strcmp( psz_method, "yadif2x" ) )
183 p_sys->i_mode = DEINTERLACE_YADIF2X;
184 p_sys->b_double_rate = true;
185 p_sys->b_half_height = false;
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_half_height = false;
193 p_sys->b_use_frame_history = true;
195 else if( !strcmp( psz_method, "ivtc" ) && p_sys->chroma->pixel_size == 1 )
197 p_sys->i_mode = DEINTERLACE_IVTC;
198 p_sys->b_double_rate = false;
199 p_sys->b_half_height = false;
200 p_sys->b_use_frame_history = true;
202 else if( !strcmp( psz_method, "discard" ) )
204 p_sys->i_mode = DEINTERLACE_DISCARD;
205 p_sys->b_double_rate = false;
206 p_sys->b_half_height = true;
207 p_sys->b_use_frame_history = false;
211 if( strcmp( psz_method, "blend" ) )
213 "no valid/compatible deinterlace mode provided, using \"blend\"" );
215 p_sys->i_mode = DEINTERLACE_BLEND;
216 p_sys->b_double_rate = false;
217 p_sys->b_half_height = false;
218 p_sys->b_use_frame_history = false;
221 p_sys->i_frame_offset = 0; /* reset to default when method changes */
223 msg_Dbg( p_filter, "using %s deinterlace method", psz_method );
226 /*****************************************************************************
227 * GetOutputFormat: return which format the chosen algorithm outputs.
228 *****************************************************************************/
230 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->i_mode == DEINTERLACE_PHOSPHOR &&
245 2 * p_sys->chroma->p[1].h.num == p_sys->chroma->p[1].h.den &&
246 2 * p_sys->chroma->p[2].h.num == p_sys->chroma->p[2].h.den &&
247 p_sys->phosphor.i_chroma_for_420 == PC_UPCONVERT )
249 p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_J420 ? VLC_CODEC_J422 :
254 p_dst->i_chroma = p_src->i_chroma;
259 /*****************************************************************************
260 * video filter2 functions
261 *****************************************************************************/
263 #define DEINTERLACE_DST_SIZE 3
265 /* This is the filter function. See Open(). */
266 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
268 filter_sys_t *p_sys = p_filter->p_sys;
269 picture_t *p_dst[DEINTERLACE_DST_SIZE];
271 /* Request output picture */
272 p_dst[0] = filter_NewPicture( p_filter );
273 if( p_dst[0] == NULL )
275 picture_Release( p_pic );
278 picture_CopyProperties( p_dst[0], p_pic );
280 /* Any unused p_dst pointers must be NULL, because they are used to
281 check how many output frames we have. */
282 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
285 /* Update the input frame history, if the currently active algorithm
287 if( p_sys->b_use_frame_history )
289 /* Duplicate the picture
290 * TODO when the vout rework is finished, picture_Hold() might be enough
291 * but becarefull, the pitches must match */
292 picture_t *p_dup = picture_NewFromFormat( &p_pic->format );
294 picture_Copy( p_dup, p_pic );
296 /* Slide the history */
297 if( p_sys->pp_history[0] )
298 picture_Release( p_sys->pp_history[0] );
299 for( int i = 1; i < HISTORY_SIZE; i++ )
300 p_sys->pp_history[i-1] = p_sys->pp_history[i];
301 p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
304 /* Slide the metadata history. */
305 for( int i = 1; i < METADATA_SIZE; i++ )
307 p_sys->meta.pi_date[i-1] = p_sys->meta.pi_date[i];
308 p_sys->meta.pi_nb_fields[i-1] = p_sys->meta.pi_nb_fields[i];
309 p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i];
311 /* The last element corresponds to the current input frame. */
312 p_sys->meta.pi_date[METADATA_SIZE-1] = p_pic->date;
313 p_sys->meta.pi_nb_fields[METADATA_SIZE-1] = p_pic->i_nb_fields;
314 p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first;
316 /* Remember the frame offset that we should use for this frame.
317 The value in p_sys will be updated to reflect the correct value
318 for the *next* frame when we call the renderer. */
319 int i_frame_offset = p_sys->i_frame_offset;
320 int i_meta_idx = (METADATA_SIZE-1) - i_frame_offset;
322 /* These correspond to the current *outgoing* frame. */
323 bool b_top_field_first;
325 if( i_frame_offset != CUSTOM_PTS )
327 /* Pick the correct values from the history. */
328 b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx];
329 i_nb_fields = p_sys->meta.pi_nb_fields[i_meta_idx];
333 /* Framerate doublers must not request CUSTOM_PTS, as they need the
334 original field timings, and need Deinterlace() to allocate the
335 correct number of output frames. */
336 assert( !p_sys->b_double_rate );
338 /* NOTE: i_nb_fields is only used for framerate doublers, so it is
339 unused in this case. b_top_field_first is only passed to the
340 algorithm. We assume that algorithms that request CUSTOM_PTS
341 will, if necessary, extract the TFF/BFF information themselves.
343 b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
345 i_nb_fields = p_pic->i_nb_fields; /* unused */
348 /* For framerate doublers, determine field duration and allocate
350 mtime_t i_field_dur = 0;
351 int i_double_rate_alloc_end = 0; /* One past last for allocated output
352 frames in p_dst[]. Used only for
353 framerate doublers. Will be inited
354 below. Declared here because the
355 PTS logic needs the result. */
356 if( p_sys->b_double_rate )
358 /* Calculate one field duration. */
360 int iend = METADATA_SIZE-1;
361 /* Find oldest valid logged date.
362 The current input frame doesn't count. */
363 for( ; i < iend; i++ )
364 if( p_sys->meta.pi_date[i] > VLC_TS_INVALID )
368 /* Count how many fields the valid history entries
369 (except the new frame) represent. */
370 int i_fields_total = 0;
371 for( int j = i ; j < iend; j++ )
372 i_fields_total += p_sys->meta.pi_nb_fields[j];
373 /* One field took this long. */
374 i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total;
376 /* Note that we default to field duration 0 if it could not be
377 determined. This behaves the same as the old code - leaving the
378 extra output frame dates the same as p_pic->date if the last cached
382 i_double_rate_alloc_end = i_nb_fields;
383 if( i_nb_fields > DEINTERLACE_DST_SIZE )
385 /* Note that the effective buffer size depends also on the constant
386 private_picture in vout_wrapper.c, since that determines the
387 maximum number of output pictures filter_NewPicture() will
388 successfully allocate for one input frame.
390 msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
391 "fields = %d, buffer size = %d. Dropping the "\
393 i_nb_fields, DEINTERLACE_DST_SIZE );
394 i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
397 /* Allocate output frames. */
398 for( int i = 1; i < i_double_rate_alloc_end ; ++i )
401 p_dst[i] = filter_NewPicture( p_filter );
404 picture_CopyProperties( p_dst[i], p_pic );
408 msg_Err( p_filter, "Framerate doubler: could not allocate "\
409 "output frame %d", i+1 );
410 i_double_rate_alloc_end = i; /* Inform the PTS logic about the
411 correct end position. */
412 break; /* If this happens, the rest of the allocations
413 aren't likely to work, either... */
416 /* Now we have allocated *up to* the correct number of frames;
417 normally, exactly the correct number. Upon alloc failure,
418 we may have succeeded in allocating *some* output frames,
419 but fewer than were desired. In such a case, as many will
420 be rendered as were successfully allocated.
422 Note that now p_dst[i] != NULL
423 for 0 <= i < i_double_rate_alloc_end. */
425 assert( p_sys->b_double_rate || p_dst[1] == NULL );
426 assert( i_nb_fields > 2 || p_dst[2] == NULL );
429 switch( p_sys->i_mode )
431 case DEINTERLACE_DISCARD:
432 RenderDiscard( p_dst[0], p_pic, 0 );
435 case DEINTERLACE_BOB:
436 RenderBob( p_dst[0], p_pic, !b_top_field_first );
438 RenderBob( p_dst[1], p_pic, b_top_field_first );
440 RenderBob( p_dst[2], p_pic, !b_top_field_first );
443 case DEINTERLACE_LINEAR:
444 RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
446 RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
448 RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
451 case DEINTERLACE_MEAN:
452 RenderMean( p_filter, p_dst[0], p_pic );
455 case DEINTERLACE_BLEND:
456 RenderBlend( p_filter, p_dst[0], p_pic );
460 RenderX( p_dst[0], p_pic );
463 case DEINTERLACE_YADIF:
464 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
468 case DEINTERLACE_YADIF2X:
469 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
472 RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
474 RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
477 case DEINTERLACE_PHOSPHOR:
478 if( RenderPhosphor( p_filter, p_dst[0], 0,
479 !b_top_field_first ) )
482 RenderPhosphor( p_filter, p_dst[1], 1,
485 RenderPhosphor( p_filter, p_dst[2], 2,
486 !b_top_field_first );
489 case DEINTERLACE_IVTC:
490 /* Note: RenderIVTC will automatically drop the duplicate frames
491 produced by IVTC. This is part of normal operation. */
492 if( RenderIVTC( p_filter, p_dst[0] ) )
497 /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
499 assert( i_frame_offset <= METADATA_SIZE || i_frame_offset == CUSTOM_PTS );
500 if( i_frame_offset != CUSTOM_PTS )
502 mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];
504 /* Note: in the usual case (i_frame_offset = 0 and
505 b_double_rate = false), this effectively does nothing.
506 This is needed to correct the timestamp
507 when i_frame_offset > 0. */
508 p_dst[0]->date = i_base_pts;
510 if( p_sys->b_double_rate )
512 /* Processing all actually allocated output frames. */
513 for( int i = 1; i < i_double_rate_alloc_end; ++i )
515 /* XXX it's not really good especially for the first picture, but
516 * I don't think that delaying by one frame is worth it */
517 if( i_base_pts > VLC_TS_INVALID )
518 p_dst[i]->date = i_base_pts + i * i_field_dur;
520 p_dst[i]->date = VLC_TS_INVALID;
525 for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
529 p_dst[i]->b_progressive = true;
530 p_dst[i]->i_nb_fields = 2;
534 picture_Release( p_pic );
538 picture_Release( p_dst[0] );
539 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
542 picture_Release( p_dst[i] );
544 picture_Release( p_pic );
548 /*****************************************************************************
550 *****************************************************************************/
552 void Flush( filter_t *p_filter )
554 filter_sys_t *p_sys = p_filter->p_sys;
556 for( int i = 0; i < METADATA_SIZE; i++ )
558 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
559 p_sys->meta.pi_nb_fields[i] = 2;
560 p_sys->meta.pb_top_field_first[i] = true;
562 p_sys->i_frame_offset = 0; /* reset to default value (first frame after
563 flush cannot have offset) */
564 for( int i = 0; i < HISTORY_SIZE; i++ )
566 if( p_sys->pp_history[i] )
567 picture_Release( p_sys->pp_history[i] );
568 p_sys->pp_history[i] = NULL;
570 IVTCClearState( p_filter );
573 /*****************************************************************************
574 * Mouse event callback
575 *****************************************************************************/
577 int Mouse( filter_t *p_filter,
578 vlc_mouse_t *p_mouse,
579 const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
583 if( p_filter->p_sys->b_half_height )
589 /*****************************************************************************
591 *****************************************************************************/
593 int Open( vlc_object_t *p_this )
595 filter_t *p_filter = (filter_t*)p_this;
598 const vlc_fourcc_t fourcc = p_filter->fmt_in.video.i_chroma;
599 const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription( fourcc );
600 if( !vlc_fourcc_IsYUV( fourcc ) ||
601 !chroma || chroma->plane_count != 3 || chroma->pixel_size > 2 )
603 msg_Err( p_filter, "Unsupported chroma (%4.4s)", (char*)&fourcc );
608 p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
612 p_sys->chroma = chroma;
613 p_sys->i_mode = DEINTERLACE_BLEND;
614 p_sys->b_double_rate = false;
615 p_sys->b_half_height = true;
616 p_sys->b_use_frame_history = false;
617 for( int i = 0; i < METADATA_SIZE; i++ )
619 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
620 p_sys->meta.pi_nb_fields[i] = 2;
621 p_sys->meta.pb_top_field_first[i] = true;
623 p_sys->i_frame_offset = 0; /* start with default value (first-ever frame
624 cannot have offset) */
625 for( int i = 0; i < HISTORY_SIZE; i++ )
626 p_sys->pp_history[i] = NULL;
628 IVTCClearState( p_filter );
630 #if defined(CAN_COMPILE_C_ALTIVEC)
631 if( chroma->pixel_size == 1 && vlc_CPU_ALTIVEC() )
632 p_sys->pf_merge = MergeAltivec;
635 #if defined(CAN_COMPILE_SSE2)
638 p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitSSE2 : Merge16BitSSE2;
639 p_sys->pf_end_merge = EndMMX;
643 #if defined(CAN_COMPILE_MMXEXT)
644 if( chroma->pixel_size == 1 && vlc_CPU_MMXEXT() )
646 p_sys->pf_merge = MergeMMXEXT;
647 p_sys->pf_end_merge = EndMMX;
651 #if defined(CAN_COMPILE_3DNOW)
652 if( chroma->pixel_size == 1 && vlc_CPU_3dNOW() )
654 p_sys->pf_merge = Merge3DNow;
655 p_sys->pf_end_merge = End3DNow;
659 #if defined(CAN_COMPILE_ARM)
660 if( vlc_CPU_ARM_NEON() )
662 (chroma->pixel_size == 1) ? merge8_arm_neon : merge16_arm_neon;
664 if( vlc_CPU_ARMv6() )
666 (chroma->pixel_size == 1) ? merge8_armv6 : merge16_armv6;
670 p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitGeneric : Merge16BitGeneric;
671 #if defined(__i386__) || defined(__x86_64__)
672 p_sys->pf_end_merge = NULL;
677 config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
680 char *psz_mode = var_GetNonEmptyString( p_filter, FILTER_CFG_PREFIX "mode" );
681 SetFilterMethod( p_filter, psz_mode );
684 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR )
686 int i_c420 = var_GetInteger( p_filter,
687 FILTER_CFG_PREFIX "phosphor-chroma" );
688 if( i_c420 != PC_LATEST && i_c420 != PC_ALTLINE &&
689 i_c420 != PC_BLEND && i_c420 != PC_UPCONVERT )
691 msg_Dbg( p_filter, "Phosphor 4:2:0 input chroma mode not set"\
692 "or out of range (valid: 1, 2, 3 or 4), "\
696 msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d",
698 /* This maps directly to the phosphor_chroma_t enum. */
699 p_sys->phosphor.i_chroma_for_420 = i_c420;
701 int i_dimmer = var_GetInteger( p_filter,
702 FILTER_CFG_PREFIX "phosphor-dimmer" );
703 if( i_dimmer < 1 || i_dimmer > 4 )
705 msg_Dbg( p_filter, "Phosphor dimmer strength not set "\
706 "or out of range (valid: 1, 2, 3 or 4), "\
708 i_dimmer = 2; /* low */
710 msg_Dbg( p_filter, "using Phosphor dimmer strength %d", i_dimmer );
711 /* The internal value ranges from 0 to 3. */
712 p_sys->phosphor.i_dimmer_strength = i_dimmer - 1;
716 p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE;
717 p_sys->phosphor.i_dimmer_strength = 1;
722 GetOutputFormat( p_filter, &fmt, &p_filter->fmt_in.video );
723 if( !p_filter->b_allow_fmt_out_change &&
724 ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma ||
725 fmt.i_height != p_filter->fmt_in.video.i_height ) )
727 Close( VLC_OBJECT(p_filter) );
730 p_filter->fmt_out.video = fmt;
731 p_filter->fmt_out.i_codec = fmt.i_chroma;
732 p_filter->pf_video_filter = Deinterlace;
733 p_filter->pf_video_flush = Flush;
734 p_filter->pf_video_mouse = Mouse;
736 msg_Dbg( p_filter, "deinterlacing" );
741 /*****************************************************************************
742 * Close: clean up the filter
743 *****************************************************************************/
745 void Close( vlc_object_t *p_this )
747 filter_t *p_filter = (filter_t*)p_this;
750 free( p_filter->p_sys );