]> git.sesse.net Git - vlc/blob - modules/video_filter/deinterlace/deinterlace.c
60b5f4503ca8a6301c6c313195124d39ba397a00
[vlc] / modules / video_filter / deinterlace / deinterlace.c
1 /*****************************************************************************
2  * deinterlace.c : deinterlacer plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2011 the VideoLAN team
5  * $Id$
6  *
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>
11  *         ...and others
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
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 General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37 #include <stdint.h>
38
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
41 #include <vlc_filter.h>
42 #include <vlc_cpu.h>
43 #include <vlc_mouse.h>
44
45 #include "deinterlace.h"
46 #include "helpers.h"
47 #include "merge.h"
48
49 /*****************************************************************************
50  * Module descriptor
51  *****************************************************************************/
52
53 #define MODE_TEXT N_("Deinterlace mode")
54 #define MODE_LONGTEXT N_("Deinterlace method to use for local playback.")
55
56 #define SOUT_MODE_TEXT N_("Streaming deinterlace mode")
57 #define SOUT_MODE_LONGTEXT N_("Deinterlace method to use for streaming.")
58
59 #define FILTER_CFG_PREFIX "sout-deinterlace-"
60
61 /* Tooltips drop linefeeds (at least in the Qt GUI);
62    thus the space before each set of consecutive \n.
63
64    See phosphor.h for phosphor_chroma_list and phosphor_dimmer_list.
65 */
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"\
70                                     "\n"\
71                                     "Latest: take chroma from new (bright) "\
72                                     "field only. Good for interlaced input, "\
73                                     "such as videos from a camcorder. \n"\
74                                     "\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"\
79                                     "\n"\
80                                     "Blend: average input field chromas. "\
81                                     "May distort the colours of the new "\
82                                     "(bright) field, too. \n"\
83                                     "\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.")
88
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. "\
94                                     "Default: Low.")
95
96 vlc_module_begin ()
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 )
102
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, 0 )
106         change_safe ()
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 )
110         change_safe ()
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 )
114         change_safe ()
115     add_shortcut( "deinterlace" )
116     set_callbacks( Open, Close )
117 vlc_module_end ()
118
119 /*****************************************************************************
120  * Local data
121  *****************************************************************************/
122
123 /**
124  * Available config options for the deinterlacer module.
125  *
126  * Note that also algorithm-specific options must be listed here,
127  * and reading logic for them implemented in Open().
128  */
129 static const char *const ppsz_filter_options[] = {
130     "mode", "phosphor-chroma", "phosphor-dimmer",
131     NULL
132 };
133
134 /*****************************************************************************
135  * SetFilterMethod: setup the deinterlace method to use.
136  *****************************************************************************/
137
138 void SetFilterMethod( filter_t *p_filter, const char *psz_method,
139                       vlc_fourcc_t i_chroma )
140 {
141     filter_sys_t *p_sys = p_filter->p_sys;
142
143     if( !psz_method )
144         psz_method = "";
145
146     if( !strcmp( psz_method, "mean" ) )
147     {
148         p_sys->i_mode = DEINTERLACE_MEAN;
149         p_sys->b_double_rate = false;
150         p_sys->b_half_height = true;
151         p_sys->b_use_frame_history = false;
152     }
153     else if( !strcmp( psz_method, "bob" )
154              || !strcmp( psz_method, "progressive-scan" ) )
155     {
156         p_sys->i_mode = DEINTERLACE_BOB;
157         p_sys->b_double_rate = true;
158         p_sys->b_half_height = false;
159         p_sys->b_use_frame_history = false;
160     }
161     else if( !strcmp( psz_method, "linear" ) )
162     {
163         p_sys->i_mode = DEINTERLACE_LINEAR;
164         p_sys->b_double_rate = true;
165         p_sys->b_half_height = false;
166         p_sys->b_use_frame_history = false;
167     }
168     else if( !strcmp( psz_method, "x" ) )
169     {
170         p_sys->i_mode = DEINTERLACE_X;
171         p_sys->b_double_rate = false;
172         p_sys->b_half_height = false;
173         p_sys->b_use_frame_history = false;
174     }
175     else if( !strcmp( psz_method, "yadif" ) )
176     {
177         p_sys->i_mode = DEINTERLACE_YADIF;
178         p_sys->b_double_rate = false;
179         p_sys->b_half_height = false;
180         p_sys->b_use_frame_history = true;
181     }
182     else if( !strcmp( psz_method, "yadif2x" ) )
183     {
184         p_sys->i_mode = DEINTERLACE_YADIF2X;
185         p_sys->b_double_rate = true;
186         p_sys->b_half_height = false;
187         p_sys->b_use_frame_history = true;
188     }
189     else if( !strcmp( psz_method, "phosphor" ) )
190     {
191         p_sys->i_mode = DEINTERLACE_PHOSPHOR;
192         p_sys->b_double_rate = true;
193         p_sys->b_half_height = false;
194         p_sys->b_use_frame_history = true;
195     }
196     else if( !strcmp( psz_method, "ivtc" ) )
197     {
198         p_sys->i_mode = DEINTERLACE_IVTC;
199         p_sys->b_double_rate = false;
200         p_sys->b_half_height = false;
201         p_sys->b_use_frame_history = true;
202     }
203     else if( !strcmp( psz_method, "discard" ) )
204     {
205         const bool b_i422 = i_chroma == VLC_CODEC_I422 ||
206                             i_chroma == VLC_CODEC_J422;
207
208         p_sys->i_mode = DEINTERLACE_DISCARD;
209         p_sys->b_double_rate = false;
210         p_sys->b_half_height = !b_i422;
211         p_sys->b_use_frame_history = false;
212     }
213     else
214     {
215         if( strcmp( psz_method, "blend" ) )
216             msg_Err( p_filter,
217                      "no valid deinterlace mode provided, using \"blend\"" );
218
219         p_sys->i_mode = DEINTERLACE_BLEND;
220         p_sys->b_double_rate = false;
221         p_sys->b_half_height = false;
222         p_sys->b_use_frame_history = false;
223     }
224
225     p_sys->i_frame_offset = 0; /* reset to default when method changes */
226
227     msg_Dbg( p_filter, "using %s deinterlace method", psz_method );
228 }
229
230 /*****************************************************************************
231  * GetOutputFormat: return which format the chosen algorithm outputs.
232  *****************************************************************************/
233
234 void GetOutputFormat( filter_t *p_filter,
235                       video_format_t *p_dst, const video_format_t *p_src )
236 {
237     filter_sys_t *p_sys = p_filter->p_sys;
238     *p_dst = *p_src;
239
240     if( p_sys->b_half_height )
241     {
242         p_dst->i_height /= 2;
243         p_dst->i_visible_height /= 2;
244         p_dst->i_y_offset /= 2;
245         p_dst->i_sar_den *= 2;
246     }
247
248     if( p_src->i_chroma == VLC_CODEC_I422 ||
249         p_src->i_chroma == VLC_CODEC_J422 )
250     {
251         switch( p_sys->i_mode )
252         {
253         case DEINTERLACE_MEAN:
254         case DEINTERLACE_LINEAR:
255         case DEINTERLACE_X:
256         case DEINTERLACE_YADIF:
257         case DEINTERLACE_YADIF2X:
258         case DEINTERLACE_PHOSPHOR:
259         case DEINTERLACE_IVTC:
260             p_dst->i_chroma = p_src->i_chroma;
261             break;
262         default:
263             p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_I422 ? VLC_CODEC_I420 :
264                                                                   VLC_CODEC_J420;
265             break;
266         }
267     }
268     else if( p_sys->i_mode == DEINTERLACE_PHOSPHOR  &&
269              p_sys->phosphor.i_chroma_for_420 == PC_UPCONVERT )
270     {
271         p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_J420 ? VLC_CODEC_J422 :
272                                                               VLC_CODEC_I422;
273     }
274 }
275
276 /*****************************************************************************
277  * IsChromaSupported: return whether the specified chroma is implemented.
278  *****************************************************************************/
279
280 bool IsChromaSupported( vlc_fourcc_t i_chroma )
281 {
282     return i_chroma == VLC_CODEC_I420 ||
283            i_chroma == VLC_CODEC_J420 ||
284            i_chroma == VLC_CODEC_YV12 ||
285            i_chroma == VLC_CODEC_I422 ||
286            i_chroma == VLC_CODEC_J422;
287 }
288
289 /*****************************************************************************
290  * video filter2 functions
291  *****************************************************************************/
292
293 #define DEINTERLACE_DST_SIZE 3
294
295 /* This is the filter function. See Open(). */
296 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
297 {
298     filter_sys_t *p_sys = p_filter->p_sys;
299     picture_t *p_dst[DEINTERLACE_DST_SIZE];
300
301     /* Request output picture */
302     p_dst[0] = filter_NewPicture( p_filter );
303     if( p_dst[0] == NULL )
304     {
305         picture_Release( p_pic );
306         return NULL;
307     }
308     picture_CopyProperties( p_dst[0], p_pic );
309
310     /* Any unused p_dst pointers must be NULL, because they are used to
311        check how many output frames we have. */
312     for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
313         p_dst[i] = NULL;
314
315     /* Update the input frame history, if the currently active algorithm
316        needs it. */
317     if( p_sys->b_use_frame_history )
318     {
319         /* Duplicate the picture
320          * TODO when the vout rework is finished, picture_Hold() might be enough
321          * but becarefull, the pitches must match */
322         picture_t *p_dup = picture_NewFromFormat( &p_pic->format );
323         if( p_dup )
324             picture_Copy( p_dup, p_pic );
325
326         /* Slide the history */
327         if( p_sys->pp_history[0] )
328             picture_Release( p_sys->pp_history[0] );
329         for( int i = 1; i < HISTORY_SIZE; i++ )
330             p_sys->pp_history[i-1] = p_sys->pp_history[i];
331         p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
332     }
333
334     /* Slide the metadata history. */
335     for( int i = 1; i < METADATA_SIZE; i++ )
336     {
337         p_sys->meta.pi_date[i-1]            = p_sys->meta.pi_date[i];
338         p_sys->meta.pi_nb_fields[i-1]       = p_sys->meta.pi_nb_fields[i];
339         p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i];
340     }
341     /* The last element corresponds to the current input frame. */
342     p_sys->meta.pi_date[METADATA_SIZE-1]            = p_pic->date;
343     p_sys->meta.pi_nb_fields[METADATA_SIZE-1]       = p_pic->i_nb_fields;
344     p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first;
345
346     /* Remember the frame offset that we should use for this frame.
347        The value in p_sys will be updated to reflect the correct value
348        for the *next* frame when we call the renderer. */
349     int i_frame_offset = p_sys->i_frame_offset;
350     int i_meta_idx     = (METADATA_SIZE-1) - i_frame_offset;
351
352     /* These correspond to the current *outgoing* frame. */
353     bool b_top_field_first;
354     int i_nb_fields;
355     if( i_frame_offset != CUSTOM_PTS )
356     {
357         /* Pick the correct values from the history. */
358         b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx];
359         i_nb_fields       = p_sys->meta.pi_nb_fields[i_meta_idx];
360     }
361     else
362     {
363         /* Framerate doublers must not request CUSTOM_PTS, as they need the
364            original field timings, and need Deinterlace() to allocate the
365            correct number of output frames. */
366         assert( !p_sys->b_double_rate );
367
368         /* NOTE: i_nb_fields is only used for framerate doublers, so it is
369                  unused in this case. b_top_field_first is only passed to the
370                  algorithm. We assume that algorithms that request CUSTOM_PTS
371                  will, if necessary, extract the TFF/BFF information themselves.
372         */
373         b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
374                                                          to be meaningful */
375         i_nb_fields       = p_pic->i_nb_fields;       /* unused */
376     }
377
378     /* For framerate doublers, determine field duration and allocate
379        output frames. */
380     mtime_t i_field_dur = 0;
381     int i_double_rate_alloc_end = 0; /* One past last for allocated output
382                                         frames in p_dst[]. Used only for
383                                         framerate doublers. Will be inited
384                                         below. Declared here because the
385                                         PTS logic needs the result. */
386     if( p_sys->b_double_rate )
387     {
388         /* Calculate one field duration. */
389         int i = 0;
390         int iend = METADATA_SIZE-1;
391         /* Find oldest valid logged date.
392            The current input frame doesn't count. */
393         for( ; i < iend; i++ )
394             if( p_sys->meta.pi_date[i] > VLC_TS_INVALID )
395                 break;
396         if( i < iend )
397         {
398             /* Count how many fields the valid history entries
399                (except the new frame) represent. */
400             int i_fields_total = 0;
401             for( int j = i ; j < iend; j++ )
402                 i_fields_total += p_sys->meta.pi_nb_fields[j];
403             /* One field took this long. */
404             i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total;
405         }
406         /* Note that we default to field duration 0 if it could not be
407            determined. This behaves the same as the old code - leaving the
408            extra output frame dates the same as p_pic->date if the last cached
409            date was not valid.
410         */
411
412         i_double_rate_alloc_end = i_nb_fields;
413         if( i_nb_fields > DEINTERLACE_DST_SIZE )
414         {
415             /* Note that the effective buffer size depends also on the constant
416                private_picture in vout_wrapper.c, since that determines the
417                maximum number of output pictures filter_NewPicture() will
418                successfully allocate for one input frame.
419             */
420             msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
421                                "fields = %d, buffer size = %d. Dropping the "\
422                                "remaining fields.",
423                                i_nb_fields, DEINTERLACE_DST_SIZE );
424             i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
425         }
426
427         /* Allocate output frames. */
428         for( int i = 1; i < i_double_rate_alloc_end ; ++i )
429         {
430             p_dst[i-1]->p_next =
431             p_dst[i]           = filter_NewPicture( p_filter );
432             if( p_dst[i] )
433             {
434                 picture_CopyProperties( p_dst[i], p_pic );
435             }
436             else
437             {
438                 msg_Err( p_filter, "Framerate doubler: could not allocate "\
439                                    "output frame %d", i+1 );
440                 i_double_rate_alloc_end = i; /* Inform the PTS logic about the
441                                                 correct end position. */
442                 break; /* If this happens, the rest of the allocations
443                           aren't likely to work, either... */
444             }
445         }
446         /* Now we have allocated *up to* the correct number of frames;
447            normally, exactly the correct number. Upon alloc failure,
448            we may have succeeded in allocating *some* output frames,
449            but fewer than were desired. In such a case, as many will
450            be rendered as were successfully allocated.
451
452            Note that now p_dst[i] != NULL
453            for 0 <= i < i_double_rate_alloc_end. */
454     }
455     assert( p_sys->b_double_rate  ||  p_dst[1] == NULL );
456     assert( i_nb_fields > 2  ||  p_dst[2] == NULL );
457
458     /* Render */
459     switch( p_sys->i_mode )
460     {
461         case DEINTERLACE_DISCARD:
462             RenderDiscard( p_filter, p_dst[0], p_pic, 0 );
463             break;
464
465         case DEINTERLACE_BOB:
466             RenderBob( p_filter, p_dst[0], p_pic, !b_top_field_first );
467             if( p_dst[1] )
468                 RenderBob( p_filter, p_dst[1], p_pic, b_top_field_first );
469             if( p_dst[2] )
470                 RenderBob( p_filter, p_dst[2], p_pic, !b_top_field_first );
471             break;;
472
473         case DEINTERLACE_LINEAR:
474             RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
475             if( p_dst[1] )
476                 RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
477             if( p_dst[2] )
478                 RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
479             break;
480
481         case DEINTERLACE_MEAN:
482             RenderMean( p_filter, p_dst[0], p_pic );
483             break;
484
485         case DEINTERLACE_BLEND:
486             RenderBlend( p_filter, p_dst[0], p_pic );
487             break;
488
489         case DEINTERLACE_X:
490             RenderX( p_dst[0], p_pic );
491             break;
492
493         case DEINTERLACE_YADIF:
494             if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
495                 goto drop;
496             break;
497
498         case DEINTERLACE_YADIF2X:
499             if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
500                 goto drop;
501             if( p_dst[1] )
502                 RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
503             if( p_dst[2] )
504                 RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
505             break;
506
507         case DEINTERLACE_PHOSPHOR:
508             if( RenderPhosphor( p_filter, p_dst[0], 0,
509                                 !b_top_field_first ) )
510                 goto drop;
511             if( p_dst[1] )
512                 RenderPhosphor( p_filter, p_dst[1], 1,
513                                 b_top_field_first );
514             if( p_dst[2] )
515                 RenderPhosphor( p_filter, p_dst[2], 2,
516                                 !b_top_field_first );
517             break;
518
519         case DEINTERLACE_IVTC:
520             /* Note: RenderIVTC will automatically drop the duplicate frames
521                      produced by IVTC. This is part of normal operation. */
522             if( RenderIVTC( p_filter, p_dst[0] ) )
523                 goto drop;
524             break;
525     }
526
527     /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
528        for this frame. */
529     assert( i_frame_offset <= METADATA_SIZE  ||  i_frame_offset == CUSTOM_PTS );
530     if( i_frame_offset != CUSTOM_PTS )
531     {
532         mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];
533
534         /* Note: in the usual case (i_frame_offset = 0  and
535                  b_double_rate = false), this effectively does nothing.
536                  This is needed to correct the timestamp
537                  when i_frame_offset > 0. */
538         p_dst[0]->date = i_base_pts;
539
540         if( p_sys->b_double_rate )
541         {
542             /* Processing all actually allocated output frames. */
543             for( int i = 1; i < i_double_rate_alloc_end; ++i )
544             {
545                 /* XXX it's not really good especially for the first picture, but
546                  * I don't think that delaying by one frame is worth it */
547                 if( i_base_pts > VLC_TS_INVALID )
548                     p_dst[i]->date = i_base_pts + i * i_field_dur;
549                 else
550                     p_dst[i]->date = VLC_TS_INVALID;
551             }
552         }
553     }
554
555     for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
556     {
557         if( p_dst[i] )
558         {
559             p_dst[i]->b_progressive = true;
560             p_dst[i]->i_nb_fields = 2;
561         }
562     }
563
564     picture_Release( p_pic );
565     return p_dst[0];
566
567 drop:
568     picture_Release( p_dst[0] );
569     for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
570     {
571         if( p_dst[i] )
572             picture_Release( p_dst[i] );
573     }
574     picture_Release( p_pic );
575     return NULL;
576 }
577
578 /*****************************************************************************
579  * Flush
580  *****************************************************************************/
581
582 void Flush( filter_t *p_filter )
583 {
584     filter_sys_t *p_sys = p_filter->p_sys;
585
586     for( int i = 0; i < METADATA_SIZE; i++ )
587     {
588         p_sys->meta.pi_date[i] = VLC_TS_INVALID;
589         p_sys->meta.pi_nb_fields[i] = 2;
590         p_sys->meta.pb_top_field_first[i] = true;
591     }
592     p_sys->i_frame_offset = 0; /* reset to default value (first frame after
593                                   flush cannot have offset) */
594     for( int i = 0; i < HISTORY_SIZE; i++ )
595     {
596         if( p_sys->pp_history[i] )
597             picture_Release( p_sys->pp_history[i] );
598         p_sys->pp_history[i] = NULL;
599     }
600     IVTCClearState( p_filter );
601 }
602
603 /*****************************************************************************
604  * Mouse event callback
605  *****************************************************************************/
606
607 int Mouse( filter_t *p_filter,
608            vlc_mouse_t *p_mouse,
609            const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
610 {
611     VLC_UNUSED(p_old);
612     *p_mouse = *p_new;
613     if( p_filter->p_sys->b_half_height )
614         p_mouse->i_y *= 2;
615     return VLC_SUCCESS;
616 }
617
618
619 /*****************************************************************************
620  * Open
621  *****************************************************************************/
622
623 int Open( vlc_object_t *p_this )
624 {
625     filter_t *p_filter = (filter_t*)p_this;
626     filter_sys_t *p_sys;
627
628     if( !IsChromaSupported( p_filter->fmt_in.video.i_chroma ) )
629         return VLC_EGENERIC;
630
631     /* */
632     p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
633     if( !p_sys )
634         return VLC_ENOMEM;
635
636     p_sys->i_mode = DEINTERLACE_BLEND;
637     p_sys->b_double_rate = false;
638     p_sys->b_half_height = true;
639     p_sys->b_use_frame_history = false;
640     for( int i = 0; i < METADATA_SIZE; i++ )
641     {
642         p_sys->meta.pi_date[i] = VLC_TS_INVALID;
643         p_sys->meta.pi_nb_fields[i] = 2;
644         p_sys->meta.pb_top_field_first[i] = true;
645     }
646     p_sys->i_frame_offset = 0; /* start with default value (first-ever frame
647                                   cannot have offset) */
648     for( int i = 0; i < HISTORY_SIZE; i++ )
649         p_sys->pp_history[i] = NULL;
650
651     IVTCClearState( p_filter );
652
653 #if defined(CAN_COMPILE_C_ALTIVEC)
654     if( vlc_CPU() & CPU_CAPABILITY_ALTIVEC )
655     {
656         p_sys->pf_merge = MergeAltivec;
657         p_sys->pf_end_merge = NULL;
658     }
659     else
660 #endif
661 #if defined(CAN_COMPILE_SSE)
662     if( vlc_CPU() & CPU_CAPABILITY_SSE2 )
663     {
664         p_sys->pf_merge = MergeSSE2;
665         p_sys->pf_end_merge = EndMMX;
666     }
667     else
668 #endif
669 #if defined(CAN_COMPILE_MMXEXT)
670     if( vlc_CPU() & CPU_CAPABILITY_MMXEXT )
671     {
672         p_sys->pf_merge = MergeMMXEXT;
673         p_sys->pf_end_merge = EndMMX;
674     }
675     else
676 #endif
677 #if defined(CAN_COMPILE_3DNOW)
678     if( vlc_CPU() & CPU_CAPABILITY_3DNOW )
679     {
680         p_sys->pf_merge = Merge3DNow;
681         p_sys->pf_end_merge = End3DNow;
682     }
683     else
684 #endif
685 #if defined __ARM_NEON__ // FIXME: runtime detect support
686     if( vlc_CPU() & CPU_CAPABILITY_NEON )
687     {
688         p_sys->pf_merge = MergeNEON;
689         p_sys->pf_end_merge = NULL;
690     }
691     else
692 #endif
693     {
694         p_sys->pf_merge = MergeGeneric;
695         p_sys->pf_end_merge = NULL;
696     }
697
698     /* */
699     config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
700                        p_filter->p_cfg );
701
702     char *psz_mode = var_GetNonEmptyString( p_filter, FILTER_CFG_PREFIX "mode" );
703     SetFilterMethod( p_filter, psz_mode, p_filter->fmt_in.video.i_chroma );
704     free( psz_mode );
705
706     if( p_sys->i_mode == DEINTERLACE_PHOSPHOR )
707     {
708         int i_c420 = var_GetInteger( p_filter,
709                                      FILTER_CFG_PREFIX "phosphor-chroma" );
710         if( i_c420 != PC_LATEST  &&  i_c420 != PC_ALTLINE  &&
711             i_c420 != PC_BLEND   && i_c420 != PC_UPCONVERT )
712         {
713             msg_Dbg( p_filter, "Phosphor 4:2:0 input chroma mode not set"\
714                                "or out of range (valid: 1, 2, 3 or 4), "\
715                                "using default" );
716             i_c420 = PC_ALTLINE;
717         }
718         msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d",
719                            i_c420 );
720         /* This maps directly to the phosphor_chroma_t enum. */
721         p_sys->phosphor.i_chroma_for_420 = i_c420;
722
723         int i_dimmer = var_GetInteger( p_filter,
724                                        FILTER_CFG_PREFIX "phosphor-dimmer" );
725         if( i_dimmer < 1  ||  i_dimmer > 4 )
726         {
727             msg_Dbg( p_filter, "Phosphor dimmer strength not set "\
728                                "or out of range (valid: 1, 2, 3 or 4), "\
729                                "using default" );
730             i_dimmer = 2; /* low */
731         }
732         msg_Dbg( p_filter, "using Phosphor dimmer strength %d", i_dimmer );
733         /* The internal value ranges from 0 to 3. */
734         p_sys->phosphor.i_dimmer_strength = i_dimmer - 1;
735     }
736     else
737     {
738         p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE;
739         p_sys->phosphor.i_dimmer_strength = 1;
740     }
741
742     /* */
743     video_format_t fmt;
744     GetOutputFormat( p_filter, &fmt, &p_filter->fmt_in.video );
745     if( !p_filter->b_allow_fmt_out_change &&
746         ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma ||
747           fmt.i_height != p_filter->fmt_in.video.i_height ) )
748     {
749         Close( VLC_OBJECT(p_filter) );
750         return VLC_EGENERIC;
751     }
752     p_filter->fmt_out.video = fmt;
753     p_filter->fmt_out.i_codec = fmt.i_chroma;
754     p_filter->pf_video_filter = Deinterlace;
755     p_filter->pf_video_flush  = Flush;
756     p_filter->pf_video_mouse  = Mouse;
757
758     msg_Dbg( p_filter, "deinterlacing" );
759
760     return VLC_SUCCESS;
761 }
762
763 /*****************************************************************************
764  * Close: clean up the filter
765  *****************************************************************************/
766
767 void Close( vlc_object_t *p_this )
768 {
769     filter_t *p_filter = (filter_t*)p_this;
770
771     Flush( p_filter );
772     free( p_filter->p_sys );
773 }