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