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