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 *****************************************************************************/
137 void SetFilterMethod( filter_t *p_filter, const char *psz_method )
139 filter_sys_t *p_sys = p_filter->p_sys;
144 p_sys->b_double_rate = false;
145 p_sys->b_half_height = false;
146 p_sys->b_use_frame_history = false;
148 if( !strcmp( psz_method, "mean" ) )
150 p_sys->i_mode = DEINTERLACE_MEAN;
151 p_sys->b_half_height = true;
153 else if( !strcmp( psz_method, "bob" )
154 || !strcmp( psz_method, "progressive-scan" ) )
156 p_sys->i_mode = DEINTERLACE_BOB;
157 p_sys->b_double_rate = true;
159 else if( !strcmp( psz_method, "linear" ) )
161 p_sys->i_mode = DEINTERLACE_LINEAR;
162 p_sys->b_double_rate = true;
164 else if( !strcmp( psz_method, "x" ) && p_sys->chroma->pixel_size == 1 )
166 p_sys->i_mode = DEINTERLACE_X;
168 else if( !strcmp( psz_method, "yadif" ) )
170 p_sys->i_mode = DEINTERLACE_YADIF;
171 p_sys->b_use_frame_history = true;
173 else if( !strcmp( psz_method, "yadif2x" ) )
175 p_sys->i_mode = DEINTERLACE_YADIF2X;
176 p_sys->b_double_rate = true;
177 p_sys->b_use_frame_history = true;
179 else if( !strcmp( psz_method, "phosphor" ) && p_sys->chroma->pixel_size == 1 )
181 p_sys->i_mode = DEINTERLACE_PHOSPHOR;
182 p_sys->b_double_rate = true;
183 p_sys->b_use_frame_history = true;
185 else if( !strcmp( psz_method, "ivtc" ) && p_sys->chroma->pixel_size == 1 )
187 p_sys->i_mode = DEINTERLACE_IVTC;
188 p_sys->b_use_frame_history = true;
190 else if( !strcmp( psz_method, "discard" ) )
192 p_sys->i_mode = DEINTERLACE_DISCARD;
193 p_sys->b_half_height = true;
197 if( strcmp( psz_method, "blend" ) )
199 "no valid/compatible deinterlace mode provided, using \"blend\"" );
201 p_sys->i_mode = DEINTERLACE_BLEND;
204 p_sys->i_frame_offset = 0; /* reset to default when method changes */
206 msg_Dbg( p_filter, "using %s deinterlace method", psz_method );
209 /*****************************************************************************
210 * GetOutputFormat: return which format the chosen algorithm outputs.
211 *****************************************************************************/
213 void GetOutputFormat( filter_t *p_filter,
214 video_format_t *p_dst, const video_format_t *p_src )
216 filter_sys_t *p_sys = p_filter->p_sys;
219 if( p_sys->b_half_height )
221 p_dst->i_height /= 2;
222 p_dst->i_visible_height /= 2;
223 p_dst->i_y_offset /= 2;
224 p_dst->i_sar_den *= 2;
227 if( p_sys->b_double_rate )
229 p_dst->i_frame_rate *= 2;
232 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR &&
233 2 * p_sys->chroma->p[1].h.num == p_sys->chroma->p[1].h.den &&
234 2 * p_sys->chroma->p[2].h.num == p_sys->chroma->p[2].h.den &&
235 p_sys->phosphor.i_chroma_for_420 == PC_UPCONVERT )
237 p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_J420 ? VLC_CODEC_J422 :
242 p_dst->i_chroma = p_src->i_chroma;
247 /*****************************************************************************
248 * video filter2 functions
249 *****************************************************************************/
251 #define DEINTERLACE_DST_SIZE 3
253 /* This is the filter function. See Open(). */
254 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
256 filter_sys_t *p_sys = p_filter->p_sys;
257 picture_t *p_dst[DEINTERLACE_DST_SIZE];
259 /* Request output picture */
260 p_dst[0] = filter_NewPicture( p_filter );
261 if( p_dst[0] == NULL )
263 picture_Release( p_pic );
266 picture_CopyProperties( p_dst[0], p_pic );
268 /* Any unused p_dst pointers must be NULL, because they are used to
269 check how many output frames we have. */
270 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
273 /* Update the input frame history, if the currently active algorithm
275 if( p_sys->b_use_frame_history )
277 /* Duplicate the picture
278 * TODO when the vout rework is finished, picture_Hold() might be enough
279 * but becarefull, the pitches must match */
280 picture_t *p_dup = picture_NewFromFormat( &p_pic->format );
282 picture_Copy( p_dup, p_pic );
284 /* Slide the history */
285 if( p_sys->pp_history[0] )
286 picture_Release( p_sys->pp_history[0] );
287 for( int i = 1; i < HISTORY_SIZE; i++ )
288 p_sys->pp_history[i-1] = p_sys->pp_history[i];
289 p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
292 /* Slide the metadata history. */
293 for( int i = 1; i < METADATA_SIZE; i++ )
295 p_sys->meta.pi_date[i-1] = p_sys->meta.pi_date[i];
296 p_sys->meta.pi_nb_fields[i-1] = p_sys->meta.pi_nb_fields[i];
297 p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i];
299 /* The last element corresponds to the current input frame. */
300 p_sys->meta.pi_date[METADATA_SIZE-1] = p_pic->date;
301 p_sys->meta.pi_nb_fields[METADATA_SIZE-1] = p_pic->i_nb_fields;
302 p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first;
304 /* Remember the frame offset that we should use for this frame.
305 The value in p_sys will be updated to reflect the correct value
306 for the *next* frame when we call the renderer. */
307 int i_frame_offset = p_sys->i_frame_offset;
308 int i_meta_idx = (METADATA_SIZE-1) - i_frame_offset;
310 /* These correspond to the current *outgoing* frame. */
311 bool b_top_field_first;
313 if( i_frame_offset != CUSTOM_PTS )
315 /* Pick the correct values from the history. */
316 b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx];
317 i_nb_fields = p_sys->meta.pi_nb_fields[i_meta_idx];
321 /* Framerate doublers must not request CUSTOM_PTS, as they need the
322 original field timings, and need Deinterlace() to allocate the
323 correct number of output frames. */
324 assert( !p_sys->b_double_rate );
326 /* NOTE: i_nb_fields is only used for framerate doublers, so it is
327 unused in this case. b_top_field_first is only passed to the
328 algorithm. We assume that algorithms that request CUSTOM_PTS
329 will, if necessary, extract the TFF/BFF information themselves.
331 b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
333 i_nb_fields = p_pic->i_nb_fields; /* unused */
336 /* For framerate doublers, determine field duration and allocate
338 mtime_t i_field_dur = 0;
339 int i_double_rate_alloc_end = 0; /* One past last for allocated output
340 frames in p_dst[]. Used only for
341 framerate doublers. Will be inited
342 below. Declared here because the
343 PTS logic needs the result. */
344 if( p_sys->b_double_rate )
346 /* Calculate one field duration. */
348 int iend = METADATA_SIZE-1;
349 /* Find oldest valid logged date.
350 The current input frame doesn't count. */
351 for( ; i < iend; i++ )
352 if( p_sys->meta.pi_date[i] > VLC_TS_INVALID )
356 /* Count how many fields the valid history entries
357 (except the new frame) represent. */
358 int i_fields_total = 0;
359 for( int j = i ; j < iend; j++ )
360 i_fields_total += p_sys->meta.pi_nb_fields[j];
361 /* One field took this long. */
362 i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total;
364 /* Note that we default to field duration 0 if it could not be
365 determined. This behaves the same as the old code - leaving the
366 extra output frame dates the same as p_pic->date if the last cached
370 i_double_rate_alloc_end = i_nb_fields;
371 if( i_nb_fields > DEINTERLACE_DST_SIZE )
373 /* Note that the effective buffer size depends also on the constant
374 private_picture in vout_wrapper.c, since that determines the
375 maximum number of output pictures filter_NewPicture() will
376 successfully allocate for one input frame.
378 msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
379 "fields = %d, buffer size = %d. Dropping the "\
381 i_nb_fields, DEINTERLACE_DST_SIZE );
382 i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
385 /* Allocate output frames. */
386 for( int i = 1; i < i_double_rate_alloc_end ; ++i )
389 p_dst[i] = filter_NewPicture( p_filter );
392 picture_CopyProperties( p_dst[i], p_pic );
396 msg_Err( p_filter, "Framerate doubler: could not allocate "\
397 "output frame %d", i+1 );
398 i_double_rate_alloc_end = i; /* Inform the PTS logic about the
399 correct end position. */
400 break; /* If this happens, the rest of the allocations
401 aren't likely to work, either... */
404 /* Now we have allocated *up to* the correct number of frames;
405 normally, exactly the correct number. Upon alloc failure,
406 we may have succeeded in allocating *some* output frames,
407 but fewer than were desired. In such a case, as many will
408 be rendered as were successfully allocated.
410 Note that now p_dst[i] != NULL
411 for 0 <= i < i_double_rate_alloc_end. */
413 assert( p_sys->b_double_rate || p_dst[1] == NULL );
414 assert( i_nb_fields > 2 || p_dst[2] == NULL );
417 switch( p_sys->i_mode )
419 case DEINTERLACE_DISCARD:
420 RenderDiscard( p_dst[0], p_pic, 0 );
423 case DEINTERLACE_BOB:
424 RenderBob( p_dst[0], p_pic, !b_top_field_first );
426 RenderBob( p_dst[1], p_pic, b_top_field_first );
428 RenderBob( p_dst[2], p_pic, !b_top_field_first );
431 case DEINTERLACE_LINEAR:
432 RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
434 RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
436 RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
439 case DEINTERLACE_MEAN:
440 RenderMean( p_filter, p_dst[0], p_pic );
443 case DEINTERLACE_BLEND:
444 RenderBlend( p_filter, p_dst[0], p_pic );
448 RenderX( p_dst[0], p_pic );
451 case DEINTERLACE_YADIF:
452 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
456 case DEINTERLACE_YADIF2X:
457 if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
460 RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
462 RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
465 case DEINTERLACE_PHOSPHOR:
466 if( RenderPhosphor( p_filter, p_dst[0], 0,
467 !b_top_field_first ) )
470 RenderPhosphor( p_filter, p_dst[1], 1,
473 RenderPhosphor( p_filter, p_dst[2], 2,
474 !b_top_field_first );
477 case DEINTERLACE_IVTC:
478 /* Note: RenderIVTC will automatically drop the duplicate frames
479 produced by IVTC. This is part of normal operation. */
480 if( RenderIVTC( p_filter, p_dst[0] ) )
485 /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
487 assert( i_frame_offset <= METADATA_SIZE || i_frame_offset == CUSTOM_PTS );
488 if( i_frame_offset != CUSTOM_PTS )
490 mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];
492 /* Note: in the usual case (i_frame_offset = 0 and
493 b_double_rate = false), this effectively does nothing.
494 This is needed to correct the timestamp
495 when i_frame_offset > 0. */
496 p_dst[0]->date = i_base_pts;
498 if( p_sys->b_double_rate )
500 /* Processing all actually allocated output frames. */
501 for( int i = 1; i < i_double_rate_alloc_end; ++i )
503 /* XXX it's not really good especially for the first picture, but
504 * I don't think that delaying by one frame is worth it */
505 if( i_base_pts > VLC_TS_INVALID )
506 p_dst[i]->date = i_base_pts + i * i_field_dur;
508 p_dst[i]->date = VLC_TS_INVALID;
513 for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
517 p_dst[i]->b_progressive = true;
518 p_dst[i]->i_nb_fields = 2;
522 picture_Release( p_pic );
526 picture_Release( p_dst[0] );
527 for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
530 picture_Release( p_dst[i] );
532 picture_Release( p_pic );
536 /*****************************************************************************
538 *****************************************************************************/
540 void Flush( filter_t *p_filter )
542 filter_sys_t *p_sys = p_filter->p_sys;
544 for( int i = 0; i < METADATA_SIZE; i++ )
546 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
547 p_sys->meta.pi_nb_fields[i] = 2;
548 p_sys->meta.pb_top_field_first[i] = true;
550 p_sys->i_frame_offset = 0; /* reset to default value (first frame after
551 flush cannot have offset) */
552 for( int i = 0; i < HISTORY_SIZE; i++ )
554 if( p_sys->pp_history[i] )
555 picture_Release( p_sys->pp_history[i] );
556 p_sys->pp_history[i] = NULL;
558 IVTCClearState( p_filter );
561 /*****************************************************************************
562 * Mouse event callback
563 *****************************************************************************/
565 int Mouse( filter_t *p_filter,
566 vlc_mouse_t *p_mouse,
567 const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
571 if( p_filter->p_sys->b_half_height )
577 /*****************************************************************************
579 *****************************************************************************/
581 int Open( vlc_object_t *p_this )
583 filter_t *p_filter = (filter_t*)p_this;
586 const vlc_fourcc_t fourcc = p_filter->fmt_in.video.i_chroma;
587 const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription( fourcc );
588 if( !vlc_fourcc_IsYUV( fourcc ) ||
589 !chroma || chroma->plane_count != 3 || chroma->pixel_size > 2 )
591 msg_Err( p_filter, "Unsupported chroma (%4.4s)", (char*)&fourcc );
596 p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
600 config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
602 char *psz_mode = var_InheritString( p_filter, FILTER_CFG_PREFIX "mode" );
603 SetFilterMethod( p_filter, psz_mode );
606 p_sys->chroma = chroma;
607 for( int i = 0; i < METADATA_SIZE; i++ )
609 p_sys->meta.pi_date[i] = VLC_TS_INVALID;
610 p_sys->meta.pi_nb_fields[i] = 2;
611 p_sys->meta.pb_top_field_first[i] = true;
613 p_sys->i_frame_offset = 0; /* start with default value (first-ever frame
614 cannot have offset) */
615 for( int i = 0; i < HISTORY_SIZE; i++ )
616 p_sys->pp_history[i] = NULL;
618 IVTCClearState( p_filter );
620 #if defined(CAN_COMPILE_C_ALTIVEC)
621 if( chroma->pixel_size == 1 && vlc_CPU_ALTIVEC() )
622 p_sys->pf_merge = MergeAltivec;
625 #if defined(CAN_COMPILE_SSE2)
628 p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitSSE2 : Merge16BitSSE2;
629 p_sys->pf_end_merge = EndMMX;
633 #if defined(CAN_COMPILE_MMXEXT)
634 if( chroma->pixel_size == 1 && vlc_CPU_MMXEXT() )
636 p_sys->pf_merge = MergeMMXEXT;
637 p_sys->pf_end_merge = EndMMX;
641 #if defined(CAN_COMPILE_3DNOW)
642 if( chroma->pixel_size == 1 && vlc_CPU_3dNOW() )
644 p_sys->pf_merge = Merge3DNow;
645 p_sys->pf_end_merge = End3DNow;
649 #if defined(CAN_COMPILE_ARM)
650 if( vlc_CPU_ARM_NEON() )
652 (chroma->pixel_size == 1) ? merge8_arm_neon : merge16_arm_neon;
654 if( vlc_CPU_ARMv6() )
656 (chroma->pixel_size == 1) ? merge8_armv6 : merge16_armv6;
660 p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitGeneric : Merge16BitGeneric;
661 #if defined(__i386__) || defined(__x86_64__)
662 p_sys->pf_end_merge = NULL;
667 if( p_sys->i_mode == DEINTERLACE_PHOSPHOR )
669 int i_c420 = var_GetInteger( p_filter,
670 FILTER_CFG_PREFIX "phosphor-chroma" );
671 if( i_c420 != PC_LATEST && i_c420 != PC_ALTLINE &&
672 i_c420 != PC_BLEND && i_c420 != PC_UPCONVERT )
674 msg_Dbg( p_filter, "Phosphor 4:2:0 input chroma mode not set"\
675 "or out of range (valid: 1, 2, 3 or 4), "\
679 msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d",
681 /* This maps directly to the phosphor_chroma_t enum. */
682 p_sys->phosphor.i_chroma_for_420 = i_c420;
684 int i_dimmer = var_GetInteger( p_filter,
685 FILTER_CFG_PREFIX "phosphor-dimmer" );
686 if( i_dimmer < 1 || i_dimmer > 4 )
688 msg_Dbg( p_filter, "Phosphor dimmer strength not set "\
689 "or out of range (valid: 1, 2, 3 or 4), "\
691 i_dimmer = 2; /* low */
693 msg_Dbg( p_filter, "using Phosphor dimmer strength %d", i_dimmer );
694 /* The internal value ranges from 0 to 3. */
695 p_sys->phosphor.i_dimmer_strength = i_dimmer - 1;
699 p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE;
700 p_sys->phosphor.i_dimmer_strength = 1;
705 GetOutputFormat( p_filter, &fmt, &p_filter->fmt_in.video );
706 if( !p_filter->b_allow_fmt_out_change &&
707 ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma ||
708 fmt.i_height != p_filter->fmt_in.video.i_height ) )
710 Close( VLC_OBJECT(p_filter) );
713 p_filter->fmt_out.video = fmt;
714 p_filter->fmt_out.i_codec = fmt.i_chroma;
715 p_filter->pf_video_filter = Deinterlace;
716 p_filter->pf_video_flush = Flush;
717 p_filter->pf_video_mouse = Mouse;
719 msg_Dbg( p_filter, "deinterlacing" );
724 /*****************************************************************************
725 * Close: clean up the filter
726 *****************************************************************************/
728 void Close( vlc_object_t *p_this )
730 filter_t *p_filter = (filter_t*)p_this;
733 free( p_filter->p_sys );