]> git.sesse.net Git - vlc/blob - modules/video_filter/deinterlace/deinterlace.c
71953d5ad1cd4e9eecc1203323f7cdc4ab195d0a
[vlc] / modules / video_filter / deinterlace / deinterlace.c
1 /*****************************************************************************
2  * deinterlace.c : deinterlacer plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2011 VLC authors and VideoLAN
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 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.
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 Lesser General Public License for more details.
22  *
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  *****************************************************************************/
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 )
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 {
140     filter_sys_t *p_sys = p_filter->p_sys;
141
142     if( !psz_method )
143         psz_method = "";
144
145     if( !strcmp( psz_method, "mean" ) )
146     {
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;
151     }
152     else if( !strcmp( psz_method, "bob" )
153              || !strcmp( psz_method, "progressive-scan" ) )
154     {
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;
159     }
160     else if( !strcmp( psz_method, "linear" ) )
161     {
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;
166     }
167     else if( !strcmp( psz_method, "x" ) && p_sys->chroma->pixel_size == 1 )
168     {
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;
173     }
174     else if( !strcmp( psz_method, "yadif" ) )
175     {
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;
180     }
181     else if( !strcmp( psz_method, "yadif2x" ) )
182     {
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;
187     }
188     else if( !strcmp( psz_method, "phosphor" ) && p_sys->chroma->pixel_size == 1 )
189     {
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;
194     }
195     else if( !strcmp( psz_method, "ivtc" ) && p_sys->chroma->pixel_size == 1 )
196     {
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;
201     }
202     else if( !strcmp( psz_method, "discard" ) )
203     {
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;
208     }
209     else
210     {
211         if( strcmp( psz_method, "blend" ) )
212             msg_Err( p_filter,
213                      "no valid/compatible deinterlace mode provided, using \"blend\"" );
214
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;
219     }
220
221     p_sys->i_frame_offset = 0; /* reset to default when method changes */
222
223     msg_Dbg( p_filter, "using %s deinterlace method", psz_method );
224 }
225
226 /*****************************************************************************
227  * GetOutputFormat: return which format the chosen algorithm outputs.
228  *****************************************************************************/
229
230 void GetOutputFormat( filter_t *p_filter,
231                       video_format_t *p_dst, const video_format_t *p_src )
232 {
233     filter_sys_t *p_sys = p_filter->p_sys;
234     *p_dst = *p_src;
235
236     if( p_sys->b_half_height )
237     {
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;
242     }
243
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 )
248     {
249         p_dst->i_chroma = p_src->i_chroma == VLC_CODEC_J420 ? VLC_CODEC_J422 :
250                                                               VLC_CODEC_I422;
251     }
252     else
253     {
254         p_dst->i_chroma = p_src->i_chroma;
255     }
256
257 }
258
259 /*****************************************************************************
260  * video filter2 functions
261  *****************************************************************************/
262
263 #define DEINTERLACE_DST_SIZE 3
264
265 /* This is the filter function. See Open(). */
266 picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
267 {
268     filter_sys_t *p_sys = p_filter->p_sys;
269     picture_t *p_dst[DEINTERLACE_DST_SIZE];
270
271     /* Request output picture */
272     p_dst[0] = filter_NewPicture( p_filter );
273     if( p_dst[0] == NULL )
274     {
275         picture_Release( p_pic );
276         return NULL;
277     }
278     picture_CopyProperties( p_dst[0], p_pic );
279
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 )
283         p_dst[i] = NULL;
284
285     /* Update the input frame history, if the currently active algorithm
286        needs it. */
287     if( p_sys->b_use_frame_history )
288     {
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 );
293         if( p_dup )
294             picture_Copy( p_dup, p_pic );
295
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;
302     }
303
304     /* Slide the metadata history. */
305     for( int i = 1; i < METADATA_SIZE; i++ )
306     {
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];
310     }
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;
315
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;
321
322     /* These correspond to the current *outgoing* frame. */
323     bool b_top_field_first;
324     int i_nb_fields;
325     if( i_frame_offset != CUSTOM_PTS )
326     {
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];
330     }
331     else
332     {
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 );
337
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.
342         */
343         b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
344                                                          to be meaningful */
345         i_nb_fields       = p_pic->i_nb_fields;       /* unused */
346     }
347
348     /* For framerate doublers, determine field duration and allocate
349        output frames. */
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 )
357     {
358         /* Calculate one field duration. */
359         int i = 0;
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 )
365                 break;
366         if( i < iend )
367         {
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;
375         }
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
379            date was not valid.
380         */
381
382         i_double_rate_alloc_end = i_nb_fields;
383         if( i_nb_fields > DEINTERLACE_DST_SIZE )
384         {
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.
389             */
390             msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
391                                "fields = %d, buffer size = %d. Dropping the "\
392                                "remaining fields.",
393                                i_nb_fields, DEINTERLACE_DST_SIZE );
394             i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
395         }
396
397         /* Allocate output frames. */
398         for( int i = 1; i < i_double_rate_alloc_end ; ++i )
399         {
400             p_dst[i-1]->p_next =
401             p_dst[i]           = filter_NewPicture( p_filter );
402             if( p_dst[i] )
403             {
404                 picture_CopyProperties( p_dst[i], p_pic );
405             }
406             else
407             {
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... */
414             }
415         }
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.
421
422            Note that now p_dst[i] != NULL
423            for 0 <= i < i_double_rate_alloc_end. */
424     }
425     assert( p_sys->b_double_rate  ||  p_dst[1] == NULL );
426     assert( i_nb_fields > 2  ||  p_dst[2] == NULL );
427
428     /* Render */
429     switch( p_sys->i_mode )
430     {
431         case DEINTERLACE_DISCARD:
432             RenderDiscard( p_dst[0], p_pic, 0 );
433             break;
434
435         case DEINTERLACE_BOB:
436             RenderBob( p_dst[0], p_pic, !b_top_field_first );
437             if( p_dst[1] )
438                 RenderBob( p_dst[1], p_pic, b_top_field_first );
439             if( p_dst[2] )
440                 RenderBob( p_dst[2], p_pic, !b_top_field_first );
441             break;;
442
443         case DEINTERLACE_LINEAR:
444             RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
445             if( p_dst[1] )
446                 RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
447             if( p_dst[2] )
448                 RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
449             break;
450
451         case DEINTERLACE_MEAN:
452             RenderMean( p_filter, p_dst[0], p_pic );
453             break;
454
455         case DEINTERLACE_BLEND:
456             RenderBlend( p_filter, p_dst[0], p_pic );
457             break;
458
459         case DEINTERLACE_X:
460             RenderX( p_dst[0], p_pic );
461             break;
462
463         case DEINTERLACE_YADIF:
464             if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
465                 goto drop;
466             break;
467
468         case DEINTERLACE_YADIF2X:
469             if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
470                 goto drop;
471             if( p_dst[1] )
472                 RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
473             if( p_dst[2] )
474                 RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
475             break;
476
477         case DEINTERLACE_PHOSPHOR:
478             if( RenderPhosphor( p_filter, p_dst[0], 0,
479                                 !b_top_field_first ) )
480                 goto drop;
481             if( p_dst[1] )
482                 RenderPhosphor( p_filter, p_dst[1], 1,
483                                 b_top_field_first );
484             if( p_dst[2] )
485                 RenderPhosphor( p_filter, p_dst[2], 2,
486                                 !b_top_field_first );
487             break;
488
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] ) )
493                 goto drop;
494             break;
495     }
496
497     /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
498        for this frame. */
499     assert( i_frame_offset <= METADATA_SIZE  ||  i_frame_offset == CUSTOM_PTS );
500     if( i_frame_offset != CUSTOM_PTS )
501     {
502         mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];
503
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;
509
510         if( p_sys->b_double_rate )
511         {
512             /* Processing all actually allocated output frames. */
513             for( int i = 1; i < i_double_rate_alloc_end; ++i )
514             {
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;
519                 else
520                     p_dst[i]->date = VLC_TS_INVALID;
521             }
522         }
523     }
524
525     for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
526     {
527         if( p_dst[i] )
528         {
529             p_dst[i]->b_progressive = true;
530             p_dst[i]->i_nb_fields = 2;
531         }
532     }
533
534     picture_Release( p_pic );
535     return p_dst[0];
536
537 drop:
538     picture_Release( p_dst[0] );
539     for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
540     {
541         if( p_dst[i] )
542             picture_Release( p_dst[i] );
543     }
544     picture_Release( p_pic );
545     return NULL;
546 }
547
548 /*****************************************************************************
549  * Flush
550  *****************************************************************************/
551
552 void Flush( filter_t *p_filter )
553 {
554     filter_sys_t *p_sys = p_filter->p_sys;
555
556     for( int i = 0; i < METADATA_SIZE; i++ )
557     {
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;
561     }
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++ )
565     {
566         if( p_sys->pp_history[i] )
567             picture_Release( p_sys->pp_history[i] );
568         p_sys->pp_history[i] = NULL;
569     }
570     IVTCClearState( p_filter );
571 }
572
573 /*****************************************************************************
574  * Mouse event callback
575  *****************************************************************************/
576
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 )
580 {
581     VLC_UNUSED(p_old);
582     *p_mouse = *p_new;
583     if( p_filter->p_sys->b_half_height )
584         p_mouse->i_y *= 2;
585     return VLC_SUCCESS;
586 }
587
588
589 /*****************************************************************************
590  * Open
591  *****************************************************************************/
592
593 int Open( vlc_object_t *p_this )
594 {
595     filter_t *p_filter = (filter_t*)p_this;
596     filter_sys_t *p_sys;
597
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 )
602     {
603         msg_Err( p_filter, "Unsupported chroma (%4.4s)", (char*)&fourcc );
604         return VLC_EGENERIC;
605     }
606
607     /* */
608     p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
609     if( !p_sys )
610         return VLC_ENOMEM;
611
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++ )
618     {
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;
622     }
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;
627
628     IVTCClearState( p_filter );
629
630 #if defined(CAN_COMPILE_C_ALTIVEC)
631     if( chroma->pixel_size == 1 && vlc_CPU_ALTIVEC() )
632         p_sys->pf_merge = MergeAltivec;
633     else
634 #endif
635 #if defined(CAN_COMPILE_SSE2)
636     if( vlc_CPU_SSE2() )
637     {
638         p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitSSE2 : Merge16BitSSE2;
639         p_sys->pf_end_merge = EndMMX;
640     }
641     else
642 #endif
643 #if defined(CAN_COMPILE_MMXEXT)
644     if( chroma->pixel_size == 1 && vlc_CPU_MMXEXT() )
645     {
646         p_sys->pf_merge = MergeMMXEXT;
647         p_sys->pf_end_merge = EndMMX;
648     }
649     else
650 #endif
651 #if defined(CAN_COMPILE_3DNOW)
652     if( chroma->pixel_size == 1 && vlc_CPU_3dNOW() )
653     {
654         p_sys->pf_merge = Merge3DNow;
655         p_sys->pf_end_merge = End3DNow;
656     }
657     else
658 #endif
659 #if defined(CAN_COMPILE_ARM)
660     if( vlc_CPU_ARM_NEON() )
661         p_sys->pf_merge =
662             (chroma->pixel_size == 1) ? merge8_arm_neon : merge16_arm_neon;
663     else
664     if( vlc_CPU_ARMv6() )
665         p_sys->pf_merge =
666             (chroma->pixel_size == 1) ? merge8_armv6 : merge16_armv6;
667     else
668 #endif
669     {
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;
673 #endif
674     }
675
676     /* */
677     config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
678                        p_filter->p_cfg );
679
680     char *psz_mode = var_GetNonEmptyString( p_filter, FILTER_CFG_PREFIX "mode" );
681     SetFilterMethod( p_filter, psz_mode );
682     free( psz_mode );
683
684     if( p_sys->i_mode == DEINTERLACE_PHOSPHOR )
685     {
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 )
690         {
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), "\
693                                "using default" );
694             i_c420 = PC_ALTLINE;
695         }
696         msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d",
697                            i_c420 );
698         /* This maps directly to the phosphor_chroma_t enum. */
699         p_sys->phosphor.i_chroma_for_420 = i_c420;
700
701         int i_dimmer = var_GetInteger( p_filter,
702                                        FILTER_CFG_PREFIX "phosphor-dimmer" );
703         if( i_dimmer < 1  ||  i_dimmer > 4 )
704         {
705             msg_Dbg( p_filter, "Phosphor dimmer strength not set "\
706                                "or out of range (valid: 1, 2, 3 or 4), "\
707                                "using default" );
708             i_dimmer = 2; /* low */
709         }
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;
713     }
714     else
715     {
716         p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE;
717         p_sys->phosphor.i_dimmer_strength = 1;
718     }
719
720     /* */
721     video_format_t fmt;
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 ) )
726     {
727         Close( VLC_OBJECT(p_filter) );
728         return VLC_EGENERIC;
729     }
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;
735
736     msg_Dbg( p_filter, "deinterlacing" );
737
738     return VLC_SUCCESS;
739 }
740
741 /*****************************************************************************
742  * Close: clean up the filter
743  *****************************************************************************/
744
745 void Close( vlc_object_t *p_this )
746 {
747     filter_t *p_filter = (filter_t*)p_this;
748
749     Flush( p_filter );
750     free( p_filter->p_sys );
751 }