]> git.sesse.net Git - vlc/blob - modules/video_filter/deinterlace/algo_yadif.c
Refactored deinterlacer module
[vlc] / modules / video_filter / deinterlace / algo_yadif.c
1 /*****************************************************************************
2  * algo_yadif.c : Wrapper for MPlayer's Yadif algorithm
3  *****************************************************************************
4  * Copyright (C) 2000-2011 the VideoLAN team
5  * $Id$
6  *
7  * Author: Sam Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #   include "config.h"
26 #endif
27
28 #ifdef CAN_COMPILE_MMXEXT
29 #   include "mmx.h"
30 #endif
31
32 #include <stdint.h>
33 #include <assert.h>
34
35 #include <vlc_common.h>
36 #include <vlc_cpu.h>
37 #include <vlc_picture.h>
38 #include <vlc_filter.h>
39
40 #include "deinterlace.h" /* filter_sys_t  */
41 #include "common.h"      /* FFMIN3 et al. */
42
43 #include "algo_yadif.h"
44
45 /*****************************************************************************
46  * Yadif (Yet Another DeInterlacing Filter).
47  *****************************************************************************/
48
49 /* Yadif's private data struct */
50 struct vf_priv_s {
51     /*
52      * 0: Output 1 frame for each frame.
53      * 1: Output 1 frame for each field.
54      * 2: Like 0 but skips spatial interlacing check.
55      * 3: Like 1 but skips spatial interlacing check.
56      *
57      * In vlc, only & 0x02 has meaning, as we do the & 0x01 ourself.
58      */
59     int mode;
60 };
61
62 /* I am unsure it is the right one */
63 typedef intptr_t x86_reg;
64
65 /* yadif.h comes from vf_yadif.c of mplayer project.
66    Necessary preprocessor macros are defined in common.h. */
67 #include "yadif.h"
68
69 int RenderYadif( filter_t *p_filter, picture_t *p_dst, picture_t *p_src,
70                  int i_order, int i_field )
71 {
72     VLC_UNUSED(p_src);
73
74     filter_sys_t *p_sys = p_filter->p_sys;
75
76     /* */
77     assert( i_order >= 0 && i_order <= 2 ); /* 2 = soft field repeat */
78     assert( i_field == 0 || i_field == 1 );
79
80     /* As the pitches must match, use ONLY pictures coming from picture_New()! */
81     picture_t *p_prev = p_sys->pp_history[0];
82     picture_t *p_cur  = p_sys->pp_history[1];
83     picture_t *p_next = p_sys->pp_history[2];
84
85     /* Account for soft field repeat.
86
87        The "parity" parameter affects the algorithm like this (from yadif.h):
88        uint8_t *prev2= parity ? prev : cur ;
89        uint8_t *next2= parity ? cur  : next;
90
91        The original parity expression that was used here is:
92        (i_field ^ (i_order == i_field)) & 1
93
94        Truth table:
95        i_field = 0, i_order = 0  => 1
96        i_field = 1, i_order = 1  => 0
97        i_field = 1, i_order = 0  => 1
98        i_field = 0, i_order = 1  => 0
99
100        => equivalent with e.g.  (1 - i_order)  or  (i_order + 1) % 2
101
102        Thus, in a normal two-field frame,
103              parity 1 = first field  (i_order == 0)
104              parity 0 = second field (i_order == 1)
105
106        Now, with three fields, where the third is a copy of the first,
107              i_order = 0  =>  parity 1 (as usual)
108              i_order = 1  =>  due to the repeat, prev = cur, but also next = cur.
109                               Because in such a case there is no motion
110                               (otherwise field repeat makes no sense),
111                               we don't actually need to invoke Yadif's filter().
112                               Thus, set "parity" to 2, and use this to bypass
113                               the filter.
114              i_order = 2  =>  parity 0 (as usual)
115     */
116     int yadif_parity;
117     if( p_cur  &&  p_cur->i_nb_fields > 2 )
118         yadif_parity = (i_order + 1) % 3; /* 1, *2*, 0; where 2 is a special
119                                              value meaning "bypass filter". */
120     else
121         yadif_parity = (i_order + 1) % 2; /* 1, 0 */
122
123     /* Filter if we have all the pictures we need */
124     if( p_prev && p_cur && p_next )
125     {
126         /* */
127         void (*filter)(struct vf_priv_s *p, uint8_t *dst,
128                        uint8_t *prev, uint8_t *cur, uint8_t *next,
129                        int w, int refs, int parity);
130 #if defined(HAVE_YADIF_SSE2)
131         if( vlc_CPU() & CPU_CAPABILITY_SSE2 )
132             filter = yadif_filter_line_mmx2;
133         else
134 #endif
135             filter = yadif_filter_line_c;
136
137         for( int n = 0; n < p_dst->i_planes; n++ )
138         {
139             const plane_t *prevp = &p_prev->p[n];
140             const plane_t *curp  = &p_cur->p[n];
141             const plane_t *nextp = &p_next->p[n];
142             plane_t *dstp        = &p_dst->p[n];
143
144             for( int y = 1; y < dstp->i_visible_lines - 1; y++ )
145             {
146                 if( (y % 2) == i_field  ||  yadif_parity == 2 )
147                 {
148                     vlc_memcpy( &dstp->p_pixels[y * dstp->i_pitch],
149                                 &curp->p_pixels[y * curp->i_pitch], dstp->i_visible_pitch );
150                 }
151                 else
152                 {
153                     struct vf_priv_s cfg;
154                     /* Spatial checks only when enough data */
155                     cfg.mode = (y >= 2 && y < dstp->i_visible_lines - 2) ? 0 : 2;
156
157                     assert( prevp->i_pitch == curp->i_pitch && curp->i_pitch == nextp->i_pitch );
158                     filter( &cfg,
159                             &dstp->p_pixels[y * dstp->i_pitch],
160                             &prevp->p_pixels[y * prevp->i_pitch],
161                             &curp->p_pixels[y * curp->i_pitch],
162                             &nextp->p_pixels[y * nextp->i_pitch],
163                             dstp->i_visible_pitch,
164                             curp->i_pitch,
165                             yadif_parity );
166                 }
167
168                 /* We duplicate the first and last lines */
169                 if( y == 1 )
170                     vlc_memcpy(&dstp->p_pixels[(y-1) * dstp->i_pitch],
171                                &dstp->p_pixels[ y    * dstp->i_pitch],
172                                dstp->i_pitch);
173                 else if( y == dstp->i_visible_lines - 2 )
174                     vlc_memcpy(&dstp->p_pixels[(y+1) * dstp->i_pitch],
175                                &dstp->p_pixels[ y    * dstp->i_pitch],
176                                dstp->i_pitch);
177             }
178         }
179
180         p_sys->i_frame_offset = 1; /* p_cur will be rendered at next frame, too */
181
182         return VLC_SUCCESS;
183     }
184     else if( !p_prev && !p_cur && p_next )
185     {
186         /* NOTE: For the first frame, we use the default frame offset
187                  as set by Open() or SetFilterMethod(). It is always 0. */
188
189         /* FIXME not good as it does not use i_order/i_field */
190         RenderX( p_dst, p_next );
191         return VLC_SUCCESS;
192     }
193     else
194     {
195         p_sys->i_frame_offset = 1; /* p_cur will be rendered at next frame */
196
197         return VLC_EGENERIC;
198     }
199 }