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