]> git.sesse.net Git - vlc/blob - modules/video_filter/panoramix.c
6d0b98c63ee0e727714f576b314f4cfe4ae3a85a
[vlc] / modules / video_filter / panoramix.c
1 /*****************************************************************************
2  * panoramix.c : Wall panoramic video with edge blending plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
5  * $Id: panoramix.c  2006-08-29 16:20:15Z ced $
6  *
7  * Authors: Cedric Cocquebert <cedric.cocquebert@supelec.fr>
8  *          based on Samuel Hocevar <sam@zoy.org>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #include <vlc/vlc.h>
30 #include <vlc_vout.h>
31
32 #include "filter_common.h"
33
34 // add by cedric.cocquebert@supelec.fr
35 #define OVERLAP        2350
36 #ifdef OVERLAP
37     #include <math.h>
38     // OS CODE DEPENDANT to get display dimensions
39     #ifdef SYS_MINGW32
40         #include <windows.h>
41     #else
42         #include <X11/Xlib.h>
43     #endif
44     #define GAMMA        1
45 //  #define PACKED_YUV    1
46     #define F2(a) ((a)*(a))
47     #define F4(a,b,x) ((a)*(F2(x))+((b)*(x)))
48     #define ACCURACY 1000
49     #define RATIO_MAX 2500
50     #define CLIP_01(a) (a < 0.0 ? 0.0 : (a > 1.0 ? 1.0 : a))
51 //    #define CLIP_0A(a) (a < 0.0 ? 0.0 : (a > ACCURACY ? ACCURACY : a))
52 #endif
53
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int  Create    ( vlc_object_t * );
58 static void Destroy   ( vlc_object_t * );
59
60 static int  Init      ( vout_thread_t * );
61 static void End       ( vout_thread_t * );
62 #ifdef PACKED_YUV
63 static void RenderPackedYUV   ( vout_thread_t *, picture_t * );
64 #endif
65 static void RenderPlanarYUV   ( vout_thread_t *, picture_t * );
66 static void RenderPackedRGB   ( vout_thread_t *, picture_t * );
67
68 static void RemoveAllVout  ( vout_thread_t *p_vout );
69
70 static int  SendEvents( vlc_object_t *, char const *,
71                         vlc_value_t, vlc_value_t, void * );
72
73 /*****************************************************************************
74  * Module descriptor
75  *****************************************************************************/
76 #define COLS_TEXT N_("Number of columns")
77 #define COLS_LONGTEXT N_("Select the number of horizontal video windows in " \
78     "which to split the video")
79
80 #define ROWS_TEXT N_("Number of rows")
81 #define ROWS_LONGTEXT N_("Select the number of vertical video windows in " \
82     "which to split the video")
83
84 #define ACTIVE_TEXT N_("Active windows")
85 #define ACTIVE_LONGTEXT N_("Comma separated list of active windows, " \
86     "defaults to all")
87
88 #define CFG_PREFIX "panoramix-"
89
90 vlc_module_begin();
91     set_description( N_("Panoramix: wall with overlap video filter") );
92     set_shortname( _("Panoramix" ));
93     set_capability( "video filter", 0 );
94     set_category( CAT_VIDEO );
95     set_subcategory( SUBCAT_VIDEO_VFILTER );
96
97     add_integer( CFG_PREFIX "cols", -1, NULL,
98                  COLS_TEXT, COLS_LONGTEXT, VLC_TRUE );
99         change_safe();
100     add_integer( CFG_PREFIX "rows", -1, NULL,
101                  ROWS_TEXT, ROWS_LONGTEXT, VLC_TRUE );
102         change_safe();
103
104 #ifdef OVERLAP
105 #define OFFSET_X_TEXT N_("Offset X offset (automatic compensation)")
106 #define OFFSET_X_LONGTEXT N_("Select if you want an automatic offset in horizontal (in case of misalignment due to autoratio control)")
107     add_bool( CFG_PREFIX "offset-x", 1, NULL, OFFSET_X_TEXT, OFFSET_X_LONGTEXT, VLC_TRUE );
108         change_safe();
109
110 #define LENGTH_TEXT N_("length of the overlapping area (in %)")
111 #define LENGTH_LONGTEXT N_("Select in percent the length of the blended zone")
112     add_integer_with_range( CFG_PREFIX "bz-length", 100, 0, 100, NULL, LENGTH_TEXT, LENGTH_LONGTEXT, VLC_TRUE );
113         change_safe();
114
115 #define HEIGHT_TEXT N_("height of the overlapping area (in %)")
116 #define HEIGHT_LONGTEXT N_("Select in percent the height of the blended zone (case of 2x2 wall)")
117     add_integer_with_range( CFG_PREFIX "bz-height", 100, 0, 100, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, VLC_TRUE );
118         change_safe();
119
120 #define ATTENUATION_TEXT N_("Attenuation")
121 #define ATTENUATION_LONGTEXT N_("Check this option if you want attenuate blended zone by this plug-in (if option is unchecked, attenuate is made by opengl)")
122     add_bool( CFG_PREFIX "attenuate", 1, NULL, ATTENUATION_TEXT, ATTENUATION_LONGTEXT, VLC_FALSE );
123         change_safe();
124
125 #define BEGIN_TEXT N_("Attenuation, begin (in %)")
126 #define BEGIN_LONGTEXT N_("Select in percent the Lagrange coeff of the beginning blended zone")
127     add_integer_with_range( CFG_PREFIX "bz-begin", 0, 0, 100, NULL, BEGIN_TEXT, BEGIN_LONGTEXT, VLC_TRUE );
128         change_safe();
129
130 #define MIDDLE_TEXT N_("Attenuation, middle (in %)")
131 #define MIDDLE_LONGTEXT N_("Select in percent the Lagrange coeff of the middle of blended zone")
132     add_integer_with_range( CFG_PREFIX "bz-middle", 50, 0, 100, NULL, MIDDLE_TEXT, MIDDLE_LONGTEXT, VLC_FALSE );
133         change_safe();
134
135 #define END_TEXT N_("Attenuation, end (in %)")
136 #define END_LONGTEXT N_("Select in percent the Lagrange coeff of the end of blended zone")
137     add_integer_with_range( CFG_PREFIX "bz-end", 100, 0, 100, NULL, END_TEXT, END_LONGTEXT, VLC_TRUE );
138         change_safe();
139
140 #define MIDDLE_POS_TEXT N_("middle position (in %)")
141 #define MIDDLE_POS_LONGTEXT N_("Select in percent (50 is center) the position of the middle point (Lagrange) of blended zone")
142     add_integer_with_range( CFG_PREFIX "bz-middle-pos", 50, 1, 99, NULL, MIDDLE_POS_TEXT, MIDDLE_POS_LONGTEXT, VLC_FALSE );
143         change_safe();
144 #ifdef GAMMA
145 #define RGAMMA_TEXT N_("Gamma (Red) correction")
146 #define RGAMMA_LONGTEXT N_("Select the gamma for the correction of blended zone (Red or Y component)")
147     add_float_with_range( CFG_PREFIX "bz-gamma-red", 1, 0, 5, NULL, RGAMMA_TEXT, RGAMMA_LONGTEXT, VLC_TRUE );
148         change_safe();
149
150 #define GGAMMA_TEXT N_("Gamma (Green) correction")
151 #define GGAMMA_LONGTEXT N_("Select the gamma for the correction of blended zone (Green or U component)")
152     add_float_with_range( CFG_PREFIX "bz-gamma-green", 1, 0, 5, NULL, GGAMMA_TEXT, GGAMMA_LONGTEXT, VLC_TRUE );
153         change_safe();
154
155 #define BGAMMA_TEXT N_("Gamma (Blue) correction")
156 #define BGAMMA_LONGTEXT N_("Select the gamma for the correction of blended zone (Blue or V component)")
157     add_float_with_range( CFG_PREFIX "bz-gamma-blue", 1, 0, 5, NULL, BGAMMA_TEXT, BGAMMA_LONGTEXT, VLC_TRUE );
158         change_safe();
159 #endif
160 #define RGAMMA_BC_TEXT N_("Black Crush for Red")
161 #define RGAMMA_BC_LONGTEXT N_("Select the Black Crush of blended zone (Red or Y component)")
162 #define GGAMMA_BC_TEXT N_("Black Crush for Green")
163 #define GGAMMA_BC_LONGTEXT N_("Select the Black Crush of blended zone (Green or U component)")
164 #define BGAMMA_BC_TEXT N_("Black Crush for Blue")
165 #define BGAMMA_BC_LONGTEXT N_("Select the Black Crush of blended zone (Blue or V component)")
166
167 #define RGAMMA_WC_TEXT N_("White Crush for Red")
168 #define RGAMMA_WC_LONGTEXT N_("Select the White Crush of blended zone (Red or Y component)")
169 #define GGAMMA_WC_TEXT N_("White Crush for Green")
170 #define GGAMMA_WC_LONGTEXT N_("Select the White Crush of blended zone (Green or U component)")
171 #define BGAMMA_WC_TEXT N_("White Crush for Blue")
172 #define BGAMMA_WC_LONGTEXT N_("Select the White Crush of blended zone (Blue or V component)")
173
174 #define RGAMMA_BL_TEXT N_("Black Level for Red")
175 #define RGAMMA_BL_LONGTEXT N_("Select the Black Level of blended zone (Red or Y component)")
176 #define GGAMMA_BL_TEXT N_("Black Level for Green")
177 #define GGAMMA_BL_LONGTEXT N_("Select the Black Level of blended zone (Green or U component)")
178 #define BGAMMA_BL_TEXT N_("Black Level for Blue")
179 #define BGAMMA_BL_LONGTEXT N_("Select the Black Level of blended zone (Blue or V component)")
180
181 #define RGAMMA_WL_TEXT N_("White Level for Red")
182 #define RGAMMA_WL_LONGTEXT N_("Select the White Level of blended zone (Red or Y component)")
183 #define GGAMMA_WL_TEXT N_("White Level for Green")
184 #define GGAMMA_WL_LONGTEXT N_("Select the White Level of blended zone (Green or U component)")
185 #define BGAMMA_WL_TEXT N_("White Level for Blue")
186 #define BGAMMA_WL_LONGTEXT N_("Select the White Level of blended zone (Blue or V component)")
187     add_integer_with_range( CFG_PREFIX "bz-blackcrush-red", 140, 0, 255, NULL, RGAMMA_BC_TEXT, RGAMMA_BC_LONGTEXT, VLC_TRUE );
188         change_safe();
189     add_integer_with_range( CFG_PREFIX "bz-blackcrush-green", 140, 0, 255, NULL, GGAMMA_BC_TEXT, GGAMMA_BC_LONGTEXT, VLC_TRUE );
190         change_safe();
191     add_integer_with_range( CFG_PREFIX "bz-blackcrush-blue", 140, 0, 255, NULL, BGAMMA_BC_TEXT, BGAMMA_BC_LONGTEXT, VLC_TRUE );
192         change_safe();
193     add_integer_with_range( CFG_PREFIX "bz-whitecrush-red", 200, 0, 255, NULL, RGAMMA_WC_TEXT, RGAMMA_WC_LONGTEXT, VLC_TRUE );
194         change_safe();
195     add_integer_with_range( CFG_PREFIX "bz-whitecrush-green", 200, 0, 255, NULL, GGAMMA_WC_TEXT, GGAMMA_WC_LONGTEXT, VLC_TRUE );
196         change_safe();
197     add_integer_with_range( CFG_PREFIX "bz-whitecrush-blue", 200, 0, 255, NULL, BGAMMA_WC_TEXT, BGAMMA_WC_LONGTEXT, VLC_TRUE );
198         change_safe();
199     add_integer_with_range( CFG_PREFIX "bz-blacklevel-red", 150, 0, 255, NULL, RGAMMA_BL_TEXT, RGAMMA_BL_LONGTEXT, VLC_TRUE );
200         change_safe();
201     add_integer_with_range( CFG_PREFIX "bz-blacklevel-green", 150, 0, 255, NULL, GGAMMA_BL_TEXT, GGAMMA_BL_LONGTEXT, VLC_TRUE );
202         change_safe();
203     add_integer_with_range( CFG_PREFIX "bz-blacklevel-blue", 150, 0, 255, NULL, BGAMMA_BL_TEXT, BGAMMA_BL_LONGTEXT, VLC_TRUE );
204         change_safe();
205     add_integer_with_range( CFG_PREFIX "bz-whitelevel-red", 0, 0, 255, NULL, RGAMMA_WL_TEXT, RGAMMA_WL_LONGTEXT, VLC_TRUE );
206         change_safe();
207     add_integer_with_range( CFG_PREFIX "bz-whitelevel-green", 0, 0, 255, NULL, GGAMMA_WL_TEXT, GGAMMA_WL_LONGTEXT, VLC_TRUE );
208         change_safe();
209     add_integer_with_range( CFG_PREFIX "bz-whitelevel-blue", 0, 0, 255, NULL, BGAMMA_WL_TEXT, BGAMMA_WL_LONGTEXT, VLC_TRUE );
210         change_safe();
211 #ifndef SYS_MINGW32
212 #define XINERAMA_TEXT N_("Xinerama option")
213 #define XINERAMA_LONGTEXT N_("Uncheck if you have not used xinerama")
214     add_bool( CFG_PREFIX "xinerama", 1, NULL, XINERAMA_TEXT, XINERAMA_LONGTEXT, VLC_TRUE );
215         change_safe();
216 #endif
217 #endif
218
219     add_string( CFG_PREFIX "active", NULL, NULL, ACTIVE_TEXT, ACTIVE_LONGTEXT, VLC_TRUE );
220         change_safe();
221
222     add_shortcut( "panoramix" );
223     set_callbacks( Create, Destroy );
224 vlc_module_end();
225
226 static const char *ppsz_filter_options[] = {
227     "cols", "rows", "offset-x", "bz-length", "bz-height", "attenuate",
228     "bz-begin", "bz-middle", "bz-end", "bz-middle-pos", "bz-gamma-red",
229     "bz-gamma-green", "bz-gamma-blue", "bz-blackcrush-red",
230     "bz-blackcrush-green", "bz-blackcrush-blue", "bz-whitecrush-red",
231     "bz-whitecrush-green", "bz-whitecrush-blue", "bz-blacklevel-red",
232     "bz-blacklevel-green", "bz-blacklevel-blue", "bz-whitelevel-red",
233     "bz-whitelevel-green", "bz-whitelevel-blue", "xinerama", "active",
234     NULL
235 };
236
237 /*****************************************************************************
238  * vout_sys_t: Wall video output method descriptor
239  *****************************************************************************
240  * This structure is part of the video output thread descriptor.
241  * It describes the Wall specific properties of an output thread.
242  *****************************************************************************/
243 struct vout_sys_t
244 {
245 #ifdef OVERLAP
246     vlc_bool_t   b_autocrop;
247     vlc_bool_t   b_attenuate;
248     unsigned int bz_length, bz_height, bz_begin, bz_middle, bz_end, bz_middle_pos;
249     unsigned int i_ratio_max;
250     unsigned int i_ratio;
251     unsigned int a_0, a_1, a_2;
252     vlc_bool_t     b_has_changed;
253     int lambda[2][VOUT_MAX_PLANES][500];
254     int cstYUV[2][VOUT_MAX_PLANES][500];
255     int lambda2[2][VOUT_MAX_PLANES][500];
256     int cstYUV2[2][VOUT_MAX_PLANES][500];
257     unsigned int i_halfLength;
258     unsigned int i_halfHeight;
259     int i_offset_x;
260     int i_offset_y;
261 #ifdef GAMMA
262     float        f_gamma_red, f_gamma_green, f_gamma_blue;
263     float         f_gamma[VOUT_MAX_PLANES];
264     uint8_t         LUT[VOUT_MAX_PLANES][ACCURACY + 1][256];
265 #ifdef PACKED_YUV
266     uint8_t         LUT2[VOUT_MAX_PLANES][256][500];
267 #endif
268 #endif
269 #ifndef SYS_MINGW32
270     vlc_bool_t   b_xinerama;
271 #endif
272 #endif
273     int    i_col;
274     int    i_row;
275     int    i_vout;
276     struct vout_list_t
277     {
278         vlc_bool_t b_active;
279         int i_width;
280         int i_height;
281         vout_thread_t *p_vout;
282     } *pp_vout;
283 };
284
285
286
287 /*****************************************************************************
288  * Control: control facility for the vout (forwards to child vout)
289  *****************************************************************************/
290 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
291 {
292     int i_row, i_col, i_vout = 0;
293
294     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
295     {
296         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
297         {
298             vout_vaControl( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
299                             i_query, args );
300             i_vout++;
301         }
302     }
303     return VLC_SUCCESS;
304 }
305
306 /*****************************************************************************
307  * Create: allocates Wall video thread output method
308  *****************************************************************************
309  * This function allocates and initializes a Wall vout method.
310  *****************************************************************************/
311 static int Create( vlc_object_t *p_this )
312 {
313     vout_thread_t *p_vout = (vout_thread_t *)p_this;
314     char *psz_method, *psz_tmp, *psz_method_tmp;
315     int i_vout;
316
317     /* Allocate structure */
318     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
319     if( p_vout->p_sys == NULL )
320     {
321         msg_Err( p_vout, "out of memory" );
322         return VLC_ENOMEM;
323     }
324
325     p_vout->pf_init = Init;
326     p_vout->pf_end = End;
327     p_vout->pf_manage = NULL;
328 /* Color Format not supported
329 // Planar Y, packed UV
330 case VLC_FOURCC('Y','M','G','A'):
331 // Packed YUV 4:2:2, U:Y:V:Y, interlaced
332 case VLC_FOURCC('I','U','Y','V'):    // packed by 2
333 // Packed YUV 2:1:1, Y:U:Y:V
334 case VLC_FOURCC('Y','2','1','1'):     // packed by 4
335 // Packed YUV Reverted
336 case VLC_FOURCC('c','y','u','v'):    // packed by 2
337 */
338     switch (p_vout->render.i_chroma)
339     {
340     // planar YUV
341         case VLC_FOURCC('I','4','4','4'):
342         case VLC_FOURCC('I','4','2','2'):
343         case VLC_FOURCC('I','4','2','0'):
344         case VLC_FOURCC('Y','V','1','2'):
345         case VLC_FOURCC('I','Y','U','V'):
346         case VLC_FOURCC('I','4','1','1'):
347         case VLC_FOURCC('I','4','1','0'):
348         case VLC_FOURCC('Y','V','U','9'):
349         case VLC_FOURCC('Y','U','V','A'):
350             p_vout->pf_render = RenderPlanarYUV;
351             break;
352     // packed RGB
353         case VLC_FOURCC('R','G','B','2'):    // packed by 1
354         case VLC_FOURCC('R','V','1','5'):    // packed by 2
355         case VLC_FOURCC('R','V','1','6'):    // packed by 2
356         case VLC_FOURCC('R','V','2','4'):    // packed by 3
357         case VLC_FOURCC('R','V','3','2'):    // packed by 4
358             p_vout->pf_render = RenderPackedRGB;
359             break;
360 #ifdef PACKED_YUV
361     // packed YUV
362         case VLC_FOURCC('Y','U','Y','2'):    // packed by 2
363         case VLC_FOURCC('Y','U','N','V'):    // packed by 2
364         case VLC_FOURCC('U','Y','V','Y'):    // packed by 2
365         case VLC_FOURCC('U','Y','N','V'):    // packed by 2
366         case VLC_FOURCC('Y','4','2','2'):    // packed by 2
367             p_vout->pf_render = RenderPackedYUV;
368             break;
369 #endif
370         default:
371             msg_Err( p_vout, "colorspace not supported by plug-in !!!");
372             free( p_vout->p_sys );
373             return VLC_ENOMEM;
374     }
375     p_vout->pf_display = NULL;
376     p_vout->pf_control = Control;
377
378     config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
379                        p_vout->p_cfg );
380
381     /* Look what method was requested */
382     p_vout->p_sys->i_col = var_CreateGetInteger( p_vout, CFG_PREFIX "cols" );
383     p_vout->p_sys->i_row = var_CreateGetInteger( p_vout, CFG_PREFIX "rows" );
384
385 // OS dependant code :  Autodetect number of displays in wall
386 #ifdef SYS_MINGW32
387     if ((p_vout->p_sys->i_col < 0) || (p_vout->p_sys->i_row < 0) )
388     {
389         int nbMonitors = GetSystemMetrics(SM_CMONITORS);
390         if (nbMonitors == 1)
391         {
392             nbMonitors = 5; // 1 display => 5x1 simulation
393             p_vout->p_sys->i_col = nbMonitors;
394             p_vout->p_sys->i_row = 1;
395         }
396         else
397         {
398             p_vout->p_sys->i_col = GetSystemMetrics( SM_CXVIRTUALSCREEN ) / GetSystemMetrics( SM_CXSCREEN );
399             p_vout->p_sys->i_row = GetSystemMetrics( SM_CYVIRTUALSCREEN ) / GetSystemMetrics( SM_CYSCREEN );
400             if (p_vout->p_sys->i_col * p_vout->p_sys->i_row != nbMonitors)
401             {
402                 p_vout->p_sys->i_col = nbMonitors;
403                 p_vout->p_sys->i_row = 1;
404             }
405         }
406         var_SetInteger( p_vout, CFG_PREFIX "cols", p_vout->p_sys->i_col);
407         var_SetInteger( p_vout, CFG_PREFIX "rows", p_vout->p_sys->i_row);
408     }
409 #endif
410
411 #ifdef OVERLAP
412     p_vout->p_sys->i_offset_x = var_CreateGetInteger( p_vout, CFG_PREFIX "offset-x" );
413     if (p_vout->p_sys->i_col > 2) p_vout->p_sys->i_offset_x = 0; // offset-x is used in case of 2x1 wall & autocrop
414     p_vout->p_sys->b_autocrop = !(var_CreateGetInteger( p_vout, "crop-ratio" ) == 0);
415     if (!p_vout->p_sys->b_autocrop) p_vout->p_sys->b_autocrop = var_CreateGetInteger( p_vout, "autocrop" );
416     p_vout->p_sys->b_attenuate = var_CreateGetInteger( p_vout, CFG_PREFIX "attenuate");
417     p_vout->p_sys->bz_length = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-length" );
418     if (p_vout->p_sys->i_row > 1)
419         p_vout->p_sys->bz_height = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-height" );
420     else
421         p_vout->p_sys->bz_height = 100;
422     p_vout->p_sys->bz_begin = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-begin" );
423     p_vout->p_sys->bz_middle = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-middle" );
424     p_vout->p_sys->bz_end = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-end" );
425     p_vout->p_sys->bz_middle_pos = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-middle-pos" );
426     double d_p = 100.0 / p_vout->p_sys->bz_middle_pos;
427     p_vout->p_sys->i_ratio_max = var_CreateGetInteger( p_vout, "autocrop-ratio-max" ); // in crop module with autocrop ...
428     p_vout->p_sys->i_ratio = var_CreateGetInteger( p_vout, "crop-ratio" ); // in crop module with manual ratio ...
429
430     p_vout->p_sys->a_2 = d_p * p_vout->p_sys->bz_begin - (double)(d_p * d_p / (d_p - 1)) * p_vout->p_sys->bz_middle + (double)(d_p / (d_p - 1)) * p_vout->p_sys->bz_end;
431     p_vout->p_sys->a_1 = -(d_p + 1) * p_vout->p_sys->bz_begin + (double)(d_p * d_p / (d_p - 1)) * p_vout->p_sys->bz_middle - (double)(1 / (d_p - 1)) * p_vout->p_sys->bz_end;
432     p_vout->p_sys->a_0 =  p_vout->p_sys->bz_begin;
433
434 #ifdef GAMMA
435     p_vout->p_sys->f_gamma_red = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-red" );
436     p_vout->p_sys->f_gamma_green = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-green" );
437     p_vout->p_sys->f_gamma_blue = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-blue" );
438 #endif
439 #ifndef SYS_MINGW32
440     p_vout->p_sys->b_xinerama= var_CreateGetInteger( p_vout, CFG_PREFIX "xinerama" );
441 #endif
442 #else
443     p_vout->p_sys->i_col = __MAX( 1, __MIN( 15, p_vout->p_sys->i_col ) );
444     p_vout->p_sys->i_row = __MAX( 1, __MIN( 15, p_vout->p_sys->i_row ) );
445 #endif
446
447     msg_Dbg( p_vout, "opening a %i x %i wall",
448              p_vout->p_sys->i_col, p_vout->p_sys->i_row );
449
450     p_vout->p_sys->pp_vout = malloc( p_vout->p_sys->i_row *
451                                      p_vout->p_sys->i_col *
452                                      sizeof(struct vout_list_t) );
453     if( p_vout->p_sys->pp_vout == NULL )
454     {
455         msg_Err( p_vout, "out of memory" );
456         free( p_vout->p_sys );
457         return VLC_ENOMEM;
458     }
459
460     psz_method_tmp =
461     psz_method = var_CreateGetNonEmptyString( p_vout, CFG_PREFIX "active" );
462
463     /* If no trailing vout are specified, take them all */
464     if( psz_method == NULL )
465     {
466         for( i_vout = p_vout->p_sys->i_row * p_vout->p_sys->i_col;
467              i_vout--; )
468         {
469             p_vout->p_sys->pp_vout[i_vout].b_active = 1;
470         }
471     }
472     /* If trailing vout are specified, activate only the requested ones */
473     else
474     {
475         for( i_vout = p_vout->p_sys->i_row * p_vout->p_sys->i_col;
476              i_vout--; )
477         {
478             p_vout->p_sys->pp_vout[i_vout].b_active = 0;
479         }
480
481         while( *psz_method )
482         {
483             psz_tmp = psz_method;
484             while( *psz_tmp && *psz_tmp != ',' )
485             {
486                 psz_tmp++;
487             }
488
489             if( *psz_tmp )
490             {
491                 *psz_tmp = '\0';
492                 i_vout = atoi( psz_method );
493                 psz_method = psz_tmp + 1;
494             }
495             else
496             {
497                 i_vout = atoi( psz_method );
498                 psz_method = psz_tmp;
499             }
500
501             if( i_vout >= 0 &&
502                 i_vout < p_vout->p_sys->i_row * p_vout->p_sys->i_col )
503             {
504                 p_vout->p_sys->pp_vout[i_vout].b_active = 1;
505             }
506         }
507     }
508
509     free( psz_method_tmp );
510
511     return VLC_SUCCESS;
512 }
513
514
515 #ifdef OVERLAP
516 /*****************************************************************************
517  * CLIP_0A: clip between 0 and ACCURACY
518  *****************************************************************************/
519 inline static int CLIP_0A( int a )
520 {
521     return (a > ACCURACY) ? ACCURACY : (a < 0) ? 0 : a;
522 }
523
524 #ifdef GAMMA
525 /*****************************************************************************
526  *  Gamma: Gamma correction
527  *****************************************************************************/
528 static double Gamma_Correction(int i_plane, float f_component, float f_BlackCrush[VOUT_MAX_PLANES], float f_WhiteCrush[VOUT_MAX_PLANES], float f_BlackLevel[VOUT_MAX_PLANES], float f_WhiteLevel[VOUT_MAX_PLANES], float f_Gamma[VOUT_MAX_PLANES])
529 {
530     float f_Input;
531
532     f_Input = (f_component * f_BlackLevel[i_plane]) / (f_BlackCrush[i_plane]) + (1.0 - f_BlackLevel[i_plane]);
533     if (f_component <= f_BlackCrush[i_plane])
534          return pow(f_Input, 1.0 / f_Gamma[i_plane]);
535     else if (f_component >= f_WhiteCrush[i_plane])
536     {
537         f_Input = (f_component * (1.0 - (f_WhiteLevel[i_plane] + 1.0)) + (f_WhiteLevel[i_plane] + 1.0) * f_WhiteCrush[i_plane] - 1.0) / (f_WhiteCrush[i_plane] - 1.0);
538         return pow(f_Input, 1.0 / f_Gamma[i_plane]);
539     }
540            else
541             return 1.0;
542 }
543
544 #ifdef PACKED_YUV
545
546 /*****************************************************************************
547  * F: Function to calculate Gamma correction
548  *****************************************************************************/
549 static uint8_t F(uint8_t i, float gamma)
550 {
551  double input = (double) i / 255.0;
552
553 // return clip(255 * pow(input, 1.0 / gamma));
554
555  if (input < 0.5)
556      return clip_uint8((255 * pow(2 * input, gamma)) / 2);
557  else
558      return clip_uint8(255 * (1 - pow(2 * (1 - input), gamma) / 2));
559
560 }
561 #endif
562 #endif
563
564 /*****************************************************************************
565  * AdjustHeight: ajust p_sys->i_height to have same BZ width for any ratio
566  *****************************************************************************/
567 static int AdjustHeight( vout_thread_t *p_vout )
568 {
569     vlc_bool_t b_fullscreen = var_CreateGetInteger( p_vout, "fullscreen" );
570     int i_window_width = p_vout->i_window_width;
571     int i_window_height = p_vout->i_window_height;
572     double d_halfLength = 0;
573     double d_halfLength_crop;
574     double d_halfLength_calculated;
575     int    i_offset = 0;
576
577 // OS DEPENDANT CODE to get display dimensions
578         if (b_fullscreen)
579         {
580 #ifdef SYS_MINGW32
581             i_window_width  = GetSystemMetrics(SM_CXSCREEN);
582             i_window_height = GetSystemMetrics(SM_CYSCREEN);
583 #else
584             Display *p_display = XOpenDisplay( "" );
585             if (p_vout->p_sys->b_xinerama)
586             {
587                 i_window_width = DisplayWidth(p_display, 0) / p_vout->p_sys->i_col;
588                 i_window_height = DisplayHeight(p_display, 0) / p_vout->p_sys->i_row;
589              }
590             else
591             {
592                 i_window_width = DisplayWidth(p_display, 0);
593                 i_window_height = DisplayHeight(p_display, 0);
594             }
595                XCloseDisplay( p_display );
596                free(p_display);
597 #endif
598         var_SetInteger( p_vout, "width", i_window_width);
599         var_SetInteger( p_vout, "height", i_window_height);
600         p_vout->i_window_width = i_window_width;
601            p_vout->i_window_height = i_window_height;
602         }
603
604         if (p_vout->p_sys->bz_length)
605         if ((!p_vout->p_sys->b_autocrop) && (!p_vout->p_sys->i_ratio))
606         {
607             if ((p_vout->p_sys->i_row > 1) || (p_vout->p_sys->i_col > 1))
608             {
609               while ((d_halfLength <= 0) || (d_halfLength > p_vout->render.i_width / (2 * p_vout->p_sys->i_col)))
610               {
611                 if (p_vout->p_sys->bz_length >= 50)
612                     d_halfLength = i_window_width * p_vout->render.i_height / (2 * i_window_height * p_vout->p_sys->i_row) - p_vout->render.i_width / (2 * p_vout->p_sys->i_col);
613                 else
614                 {
615                     d_halfLength = (p_vout->render.i_width * p_vout->p_sys->bz_length) / (100.0 * p_vout->p_sys->i_col);
616                     d_halfLength = __MAX(i_window_width * p_vout->render.i_height / (2 * i_window_height * p_vout->p_sys->i_row) - p_vout->render.i_width / (2 * p_vout->p_sys->i_col), d_halfLength);
617                 }
618                 if ((d_halfLength <= 0) || (d_halfLength > p_vout->render.i_width / (2 * p_vout->p_sys->i_col))) p_vout->p_sys->i_row--;
619                 if (p_vout->p_sys->i_row < 1 )
620                 {
621                     p_vout->p_sys->i_row = 1;
622                     break;
623                 }
624               }
625               p_vout->p_sys->i_halfLength = (d_halfLength + 0.5);
626               p_vout->p_sys->bz_length = (p_vout->p_sys->i_halfLength * 100.0 * p_vout->p_sys->i_col) / p_vout->render.i_width;
627               var_SetInteger( p_vout, "bz-length", p_vout->p_sys->bz_length);
628               var_SetInteger( p_vout, "panoramix-rows", p_vout->p_sys->i_row);
629               }
630         }
631         else
632         {
633             d_halfLength = ((2 * (double)i_window_width - (double)(p_vout->p_sys->i_ratio_max * i_window_height) / 1000.0 ) * (double)p_vout->p_sys->bz_length) / 200.0;
634             d_halfLength_crop = d_halfLength * VOUT_ASPECT_FACTOR * (double)p_vout->output.i_width
635                         / (double)i_window_height / (double)p_vout->render.i_aspect;
636             p_vout->p_sys->i_halfLength = (d_halfLength_crop + 0.5);
637             d_halfLength_calculated = p_vout->p_sys->i_halfLength * (double)i_window_height *
638                                 (double)p_vout->render.i_aspect  /     VOUT_ASPECT_FACTOR / (double)p_vout->output.i_width;
639
640             if (!p_vout->p_sys->b_attenuate)
641             {
642                 double d_bz_length = (p_vout->p_sys->i_halfLength * p_vout->p_sys->i_col * 100.0) / p_vout->render.i_width;
643                 // F(2x) != 2F(x) in opengl module
644                 if (p_vout->p_sys->i_col == 2) d_bz_length = (100.0 * d_bz_length) / (100.0 - d_bz_length) ;
645                 var_SetInteger( p_vout, "bz-length", (int)(d_bz_length + 0.5));
646             }
647             i_offset =  (int)d_halfLength - (int)
648                         (p_vout->p_sys->i_halfLength * (double)i_window_height *
649                         (double)p_vout->render.i_aspect  /     VOUT_ASPECT_FACTOR / (double)p_vout->output.i_width);
650         }
651         else
652             d_halfLength = 0;
653
654         return i_offset;
655 }
656 #endif
657
658
659 /*****************************************************************************
660  * Init: initialize Wall video thread output method
661  *****************************************************************************/
662 static int Init( vout_thread_t *p_vout )
663 {
664     int i_index, i_row, i_col, i_width, i_height;
665     picture_t *p_pic;
666
667     I_OUTPUTPICTURES = 0;
668
669     /* Initialize the output structure */
670     p_vout->output.i_chroma = p_vout->render.i_chroma;
671     p_vout->output.i_width  = p_vout->render.i_width;
672     p_vout->output.i_height = p_vout->render.i_height;
673     p_vout->output.i_aspect = p_vout->render.i_aspect;
674 #ifdef OVERLAP
675     p_vout->p_sys->b_has_changed = p_vout->p_sys->b_attenuate;
676     int i_video_x = var_GetInteger( p_vout, "video-x");
677     int i_video_y = var_GetInteger( p_vout, "video-y");
678 #ifdef GAMMA
679     if (p_vout->p_sys->b_attenuate)
680     {
681         int i_index2, i_plane;
682         int constantYUV[3] = {0,128,128};
683         float    f_BlackCrush[VOUT_MAX_PLANES];
684         float    f_BlackLevel[VOUT_MAX_PLANES];
685         float    f_WhiteCrush[VOUT_MAX_PLANES];
686         float    f_WhiteLevel[VOUT_MAX_PLANES];
687         p_vout->p_sys->f_gamma[0] = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-red" );
688         p_vout->p_sys->f_gamma[1] = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-green" );
689         p_vout->p_sys->f_gamma[2] = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-blue" );
690         f_BlackCrush[0] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blackcrush-red" ) / 255.0;
691         f_BlackCrush[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blackcrush-green" ) / 255.0;
692         f_BlackCrush[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blackcrush-blue" ) / 255.0;
693         f_WhiteCrush[0] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitecrush-red" ) / 255.0;
694         f_WhiteCrush[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitecrush-green" ) / 255.0;
695         f_WhiteCrush[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitecrush-blue" ) / 255.0;
696         f_BlackLevel[0] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blacklevel-red" ) / 255.0;
697         f_BlackLevel[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blacklevel-green" ) / 255.0;
698         f_BlackLevel[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blacklevel-blue" ) / 255.0;
699         f_WhiteLevel[0] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitelevel-red" ) / 255.0;
700         f_WhiteLevel[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitelevel-green" ) / 255.0;
701         f_WhiteLevel[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitelevel-blue" ) / 255.0;
702         switch (p_vout->render.i_chroma)
703         {
704         // planar YVU
705             case VLC_FOURCC('Y','V','1','2'):
706             case VLC_FOURCC('Y','V','U','9'):
707         // packed UYV
708             case VLC_FOURCC('U','Y','V','Y'):    // packed by 2
709             case VLC_FOURCC('U','Y','N','V'):    // packed by 2
710             case VLC_FOURCC('Y','4','2','2'):    // packed by 2
711     //        case VLC_FOURCC('c','y','u','v'):    // packed by 2
712                 p_vout->p_sys->f_gamma[2] = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-green" );
713                 p_vout->p_sys->f_gamma[1] = var_CreateGetFloat( p_vout, CFG_PREFIX "bz-gamma-blue" );
714                 f_BlackCrush[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blackcrush-green" ) / 255.0;
715                 f_BlackCrush[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blackcrush-blue" ) / 255.0;
716                 f_WhiteCrush[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitecrush-green" ) / 255.0;
717                 f_WhiteCrush[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitecrush-blue" ) / 255.0;
718                 f_BlackLevel[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blacklevel-green" ) / 255.0;
719                 f_BlackLevel[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-blacklevel-blue" ) / 255.0;
720                 f_WhiteLevel[2] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitelevel-green" ) / 255.0;
721                 f_WhiteLevel[1] = var_CreateGetInteger( p_vout, CFG_PREFIX "bz-whitelevel-blue" ) / 255.0;
722         // planar YUV
723             case VLC_FOURCC('I','4','4','4'):
724             case VLC_FOURCC('I','4','2','2'):
725             case VLC_FOURCC('I','4','2','0'):
726             case VLC_FOURCC('I','4','1','1'):
727             case VLC_FOURCC('I','4','1','0'):
728             case VLC_FOURCC('I','Y','U','V'):
729             case VLC_FOURCC('Y','U','V','A'):
730         // packed YUV
731             case VLC_FOURCC('Y','U','Y','2'):    // packed by 2
732             case VLC_FOURCC('Y','U','N','V'):    // packed by 2
733                 for (i_index = 0; i_index < 256; i_index++)
734                     for (i_index2 = 0; i_index2 <= ACCURACY; i_index2++)
735                         for (i_plane = 0; i_plane < VOUT_MAX_PLANES; i_plane++)
736                         {
737                             float f_lut = CLIP_01(1.0 -
738                                      ((ACCURACY - (float)i_index2)
739                                      * Gamma_Correction(i_plane, (float)i_index / 255.0, f_BlackCrush, f_WhiteCrush, f_BlackLevel, f_WhiteLevel, p_vout->p_sys->f_gamma)
740                                      / (ACCURACY - 1)));
741                             p_vout->p_sys->LUT[i_plane][i_index2][i_index] = f_lut * i_index + (int)((1.0 - f_lut) * (float)constantYUV[i_plane]);
742                         }
743                 break;
744         // packed RGB
745             case VLC_FOURCC('R','G','B','2'):    // packed by 1
746             case VLC_FOURCC('R','V','1','5'):    // packed by 2
747             case VLC_FOURCC('R','V','1','6'):    // packed by 2
748             case VLC_FOURCC('R','V','2','4'):    // packed by 3
749             case VLC_FOURCC('R','V','3','2'):    // packed by 4
750             for (i_index = 0; i_index < 256; i_index++)
751                     for (i_index2 = 0; i_index2 <= ACCURACY; i_index2++)
752                         for (i_plane = 0; i_plane < VOUT_MAX_PLANES; i_plane++)
753                         {
754                             float f_lut = CLIP_01(1.0 -
755                                      ((ACCURACY - (float)i_index2)
756                                      * Gamma_Correction(i_plane, (float)i_index / 255.0, f_BlackCrush, f_WhiteCrush, f_BlackLevel, f_WhiteLevel, p_vout->p_sys->f_gamma)
757                                      / (ACCURACY - 1)));
758                             p_vout->p_sys->LUT[i_plane][i_index2][i_index] = f_lut * i_index;
759                         }
760                 break;
761             default:
762                 msg_Err( p_vout, "colorspace not supported by plug-in !!!");
763                 free( p_vout->p_sys );
764                 return VLC_ENOMEM;
765         }
766     }
767 #endif
768     if (p_vout->p_sys->i_offset_x)
769         p_vout->p_sys->i_offset_x = AdjustHeight(p_vout);
770     else
771         AdjustHeight(p_vout);
772 #endif
773
774     /* Try to open the real video output */
775     msg_Dbg( p_vout, "spawning the real video outputs" );
776
777     p_vout->p_sys->i_vout = 0;
778
779     /* FIXME: use bresenham instead of those ugly divisions */
780     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
781     {
782         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
783         {
784             video_format_t fmt;
785
786             memset( &fmt, 0, sizeof(video_format_t) );
787
788             if( i_col + 1 < p_vout->p_sys->i_col )
789             {
790                 i_width = ( p_vout->render.i_width
791                              / p_vout->p_sys->i_col ) & ~0x1;
792             }
793             else
794             {
795                 i_width = p_vout->render.i_width
796                            - ( ( p_vout->render.i_width
797                                   / p_vout->p_sys->i_col ) & ~0x1 ) * i_col;
798
799             }
800 #ifdef OVERLAP
801             i_width += p_vout->p_sys->i_halfLength;
802             if (p_vout->p_sys->i_col > 2 ) i_width += p_vout->p_sys->i_halfLength;
803             i_width -= i_width % 2;
804 #endif
805             if( i_row + 1 < p_vout->p_sys->i_row )
806             {
807                 i_height = ( p_vout->render.i_height
808                               / p_vout->p_sys->i_row ) & ~0x3;
809             }
810             else
811             {
812                 i_height = p_vout->render.i_height
813                             - ( ( p_vout->render.i_height
814                                    / p_vout->p_sys->i_row ) & ~0x3 ) * i_row;
815             }
816
817 #ifdef OVERLAP
818             if (p_vout->p_sys->i_row >= 2)
819             {
820                 p_vout->p_sys->i_halfHeight = (p_vout->p_sys->i_halfLength * p_vout->p_sys->bz_height) / 100;
821                 p_vout->p_sys->i_halfHeight -= (p_vout->p_sys->i_halfHeight % 2);
822                 i_height += p_vout->p_sys->i_halfHeight;
823                 if (p_vout->p_sys->i_row > 2) i_height += p_vout->p_sys->i_halfHeight;
824             }
825             i_height -= i_height % 2;
826 #endif
827             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].i_width = i_width;
828             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].i_height = i_height;
829
830             if( !p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].b_active )
831             {
832                 p_vout->p_sys->i_vout++;
833                 continue;
834             }
835
836             fmt.i_width = fmt.i_visible_width = p_vout->render.i_width;
837             fmt.i_height = fmt.i_visible_height = p_vout->render.i_height;
838             fmt.i_x_offset = fmt.i_y_offset = 0;
839             fmt.i_chroma = p_vout->render.i_chroma;
840             fmt.i_aspect = p_vout->render.i_aspect;
841             fmt.i_sar_num = p_vout->render.i_aspect * fmt.i_height / fmt.i_width;
842             fmt.i_sar_den = VOUT_ASPECT_FACTOR;
843             fmt.i_width = fmt.i_visible_width = i_width;
844             fmt.i_height = fmt.i_visible_height = i_height;
845             fmt.i_aspect = p_vout->render.i_aspect
846                               * p_vout->render.i_height / i_height
847                               * i_width / p_vout->render.i_width;
848 #ifdef OVERLAP
849             if (p_vout->p_sys->i_offset_x < 0)
850             {
851                 var_SetInteger(p_vout, "video-x", -p_vout->p_sys->i_offset_x);
852                 p_vout->p_sys->i_offset_x = 0;
853             }
854 #endif
855             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout =
856                 vout_Create( p_vout, &fmt);
857
858             if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout == NULL )
859             {
860                 msg_Err( p_vout, "failed to get %ix%i vout threads",
861                                  p_vout->p_sys->i_col, p_vout->p_sys->i_row );
862                 RemoveAllVout( p_vout );
863                 return VLC_EGENERIC;
864             }
865             ADD_CALLBACKS(
866                 p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout,
867                 SendEvents );
868 #ifdef OVERLAP
869             p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout->i_alignment = 0;
870             if (i_col == 0) p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout->i_alignment |= VOUT_ALIGN_RIGHT;
871             else if (i_col == p_vout->p_sys->i_col -1) p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout->i_alignment |= VOUT_ALIGN_LEFT;
872             if (p_vout->p_sys->i_row > 1)
873             {
874                 if (i_row == 0) p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout->i_alignment |= VOUT_ALIGN_BOTTOM;
875                 else if (i_row == p_vout->p_sys->i_row -1) p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout->i_alignment |= VOUT_ALIGN_TOP;
876             }
877     // i_n : number of active pp_vout
878             int i_index, i_n = p_vout->p_sys->i_vout;
879                 for (i_index = p_vout->p_sys->i_vout; i_index >= 0; i_index--) if (!p_vout->p_sys->pp_vout[i_index].b_active) i_n -= 1;
880             var_SetInteger( p_vout, "align", p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout->i_alignment );
881             var_SetInteger( p_vout, "video-x",i_video_x + p_vout->p_sys->i_offset_x + ((i_n + 1) % p_vout->p_sys->i_col) * p_vout->i_window_width);
882             var_SetInteger( p_vout, "video-y",i_video_y + ((i_n + 1) / p_vout->p_sys->i_col) * p_vout->i_window_height);
883 #endif
884             p_vout->p_sys->i_vout++;
885         }
886     }
887
888     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
889
890     ADD_PARENT_CALLBACKS( SendEventsToChild );
891
892     return VLC_SUCCESS;
893 }
894
895 /*****************************************************************************
896  * End: terminate Wall video thread output method
897  *****************************************************************************/
898 static void End( vout_thread_t *p_vout )
899 {
900     int i_index;
901
902 #ifdef OVERLAP
903     var_SetInteger( p_vout, "bz-length", p_vout->p_sys->bz_length);
904 #endif
905     /* Free the fake output buffers we allocated */
906     for( i_index = I_OUTPUTPICTURES ; i_index ; )
907     {
908         i_index--;
909         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
910     }
911 }
912
913 /*****************************************************************************
914  * Destroy: destroy Wall video thread output method
915  *****************************************************************************
916  * Terminate an output method created by WallCreateOutputMethod
917  *****************************************************************************/
918 static void Destroy( vlc_object_t *p_this )
919 {
920     vout_thread_t *p_vout = (vout_thread_t *)p_this;
921
922 #ifdef GLOBAL_OUTPUT
923     DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents);
924     vlc_object_detach( p_vout->p_sys->p_vout );
925     vout_Destroy( p_vout->p_sys->p_vout );
926     DEL_PARENT_CALLBACKS( SendEventsToChild);
927 #endif
928
929     RemoveAllVout( p_vout );
930     DEL_PARENT_CALLBACKS( SendEventsToChild );
931
932     free( p_vout->p_sys->pp_vout );
933     free( p_vout->p_sys );
934
935 }
936
937 /*****************************************************************************
938  * RenderPlanarYUV: displays previously rendered output
939  *****************************************************************************
940  * This function send the currently rendered image to Wall image, waits
941  * until it is displayed and switch the two rendering buffers, preparing next
942  * frame.
943  *****************************************************************************/
944 static void RenderPlanarYUV( vout_thread_t *p_vout, picture_t *p_pic )
945 {
946     picture_t *p_outpic = NULL;
947     int i_col, i_row, i_vout, i_plane;
948     int pi_left_skip[VOUT_MAX_PLANES], pi_top_skip[VOUT_MAX_PLANES];
949 #ifdef OVERLAP
950     int LeftOffset, TopOffset;
951     int constantYUV[3] = {0,128,128};
952     int Denom;
953     int a_2;
954     int a_1;
955     int a_0;
956     int i_index, i_index2;
957 #endif
958
959
960     i_vout = 0;
961
962     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
963     {
964         pi_top_skip[i_plane] = 0;
965     }
966
967     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
968     {
969         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
970         {
971             pi_left_skip[i_plane] = 0;
972         }
973
974         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
975         {
976             if( !p_vout->p_sys->pp_vout[ i_vout ].b_active )
977             {
978                 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
979                 {
980                     pi_left_skip[i_plane] +=
981                         p_vout->p_sys->pp_vout[ i_vout ].i_width
982                          * p_pic->p[i_plane].i_pitch / p_vout->output.i_width;
983                 }
984                 i_vout++;
985                 continue;
986             }
987
988             while( ( p_outpic =
989                 vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
990                                     0, 0, 0 )
991                    ) == NULL )
992             {
993                 if( p_vout->b_die || p_vout->b_error )
994                 {
995                     vout_DestroyPicture(
996                         p_vout->p_sys->pp_vout[ i_vout ].p_vout, p_outpic );
997                     return;
998                 }
999
1000                 msleep( VOUT_OUTMEM_SLEEP );
1001             }
1002
1003             vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1004                               p_outpic, p_pic->date );
1005             vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1006                               p_outpic );
1007
1008             for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1009             {
1010                 uint8_t *p_in, *p_in_end, *p_out;
1011                 int i_in_pitch = p_pic->p[i_plane].i_pitch;
1012                 int i_out_pitch = p_outpic->p[i_plane].i_pitch;
1013                 int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
1014                 int i_lines = p_outpic->p[i_plane].i_visible_lines;
1015 #ifdef OVERLAP
1016                 if (i_col) pi_left_skip[i_plane] -= (2 * p_vout->p_sys->i_halfLength ) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1017                 if ((i_row) && (!i_col)) pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * p_pic->p[i_plane].i_pitch) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1018                 if ((p_vout->p_sys->i_row > 2) && (i_row == 1) && (!i_col)) pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * p_pic->p[i_plane].i_pitch) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1019                 if ((!p_vout->p_sys->pp_vout[p_vout->p_sys->i_col].b_active))
1020                     pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * i_row * p_pic->p[i_plane].i_pitch) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1021 // i_n : previous inactive pp_vout
1022                 int i_n=0;
1023                 while ((!p_vout->p_sys->pp_vout[i_row * p_vout->p_sys->i_col + i_col - 1 - i_n].b_active) && (i_col - i_n > 1)) i_n++;
1024                 if ((i_col > 1) && i_n)
1025                     pi_left_skip[i_plane] -= i_n*(2 * p_vout->p_sys->i_halfLength ) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1026
1027                 p_in = p_pic->p[i_plane].p_pixels
1028                 /* Wall proprities */
1029                 + pi_top_skip[i_plane] + pi_left_skip[i_plane];
1030
1031                 if ((p_vout->p_sys->i_row > 2) &&
1032                     ((!i_row) || (i_row + 1 == p_vout->p_sys->i_row)))
1033                         i_lines -= (2 * p_vout->p_sys->i_halfHeight) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1034
1035 // 1088 lines bug in a mpeg2 stream of 1080 lines
1036                 if ((p_vout->p_sys->i_row - 1 == i_row) &&
1037                     (p_pic->p[i_plane].i_lines == 1088))
1038                         i_lines -= 8 / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1039
1040                 p_in_end = p_in + i_lines * p_pic->p[i_plane].i_pitch;
1041 #else
1042                 p_in = p_pic->p[i_plane].p_pixels
1043                         + pi_top_skip[i_plane] + pi_left_skip[i_plane];
1044
1045                 p_in_end = p_in + i_lines * p_pic->p[i_plane].i_pitch;
1046 #endif
1047                 p_out = p_outpic->p[i_plane].p_pixels;
1048 #ifdef OVERLAP
1049         if ((p_vout->p_sys->i_row > 2) && (!i_row))
1050             p_out += (p_outpic->p[i_plane].i_pitch * (2 * p_vout->p_sys->i_halfHeight) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch));
1051
1052         int length;
1053         int i_col_mod;
1054         length = 2 * p_vout->p_sys->i_halfLength / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1055
1056         if (p_vout->p_sys->b_has_changed)
1057         {
1058             Denom = F2(length);
1059             a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1060             a_1 = p_vout->p_sys->a_1 * length * (ACCURACY / 100);
1061             a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1062             for(i_col_mod = 0; i_col_mod < 2; i_col_mod++)
1063              for (i_index = 0; i_index < length; i_index++)
1064              {
1065                 p_vout->p_sys->lambda[i_col_mod][i_plane][i_index] = CLIP_0A(!i_col_mod ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,length - i_index) + a_0) / Denom);
1066                 p_vout->p_sys->cstYUV[i_col_mod][i_plane][i_index] = ((ACCURACY - p_vout->p_sys->lambda[i_col_mod][i_plane][i_index]) * constantYUV[i_plane]) / ACCURACY;
1067              }
1068         }
1069 #endif
1070             while( p_in < p_in_end )
1071             {
1072 #ifndef OVERLAP
1073                 p_vout->p_libvlc->pf_memcpy( p_out , p_in, i_copy_pitch);
1074 #else
1075                 if (p_vout->p_sys->i_col > 2)
1076                 {
1077                     length /= 2;
1078                     if (i_col == 0)
1079                         p_vout->p_libvlc->pf_memcpy( p_out + length , p_in, i_copy_pitch - length);
1080                     else if (i_col + 1 == p_vout->p_sys->i_col)
1081                             p_vout->p_libvlc->pf_memcpy( p_out, p_in - length, i_copy_pitch - length);
1082                          else
1083                             p_vout->p_libvlc->pf_memcpy( p_out, p_in - length, i_copy_pitch);
1084
1085                     if ((i_col == 0))
1086                     // black bar
1087                     {
1088                         LeftOffset = 0;
1089                         p_out += LeftOffset;
1090                         memset(p_out, constantYUV[i_plane], length);
1091                         p_out -= LeftOffset;
1092                     }
1093                     else if ((i_col + 1 == p_vout->p_sys->i_col ))
1094                     // black bar
1095                         {
1096                             LeftOffset = i_copy_pitch - length;
1097                             p_out += LeftOffset;
1098                             memset(p_out, constantYUV[i_plane], length);
1099                             p_out -= LeftOffset;
1100                         }
1101                     length *= 2;
1102                 }
1103                 else
1104                     p_vout->p_libvlc->pf_memcpy( p_out , p_in, i_copy_pitch);
1105
1106               if (p_vout->p_sys->b_attenuate)
1107             {
1108 // vertical blend
1109 // first blended zone
1110                 if (i_col)
1111                 {
1112                     LeftOffset = 0;
1113                     p_out += LeftOffset;
1114                     for (i_index = 0; i_index < length; i_index++)
1115                     {
1116 #ifndef GAMMA
1117                         *(p_out + i_index) = (p_vout->p_sys->lambda[1][i_plane][i_index] *
1118                                  (*(p_out + i_index))) / ACCURACY +
1119                                      p_vout->p_sys->cstYUV[1][i_plane][i_index];
1120 #else
1121                             *(p_out + i_index) = p_vout->p_sys->LUT[i_plane][p_vout->p_sys->lambda[1][i_plane][i_index]][*(p_out + i_index)];
1122 #endif
1123                     }
1124                     p_out -= LeftOffset;
1125                 }
1126 // second blended zone
1127                 if (i_col + 1 < p_vout->p_sys->i_col)
1128                 {
1129                     LeftOffset = i_copy_pitch - length;
1130                     p_out +=  LeftOffset;
1131                     for (i_index = 0; i_index < length; i_index++)
1132                     {
1133 #ifndef GAMMA
1134                             *(p_out + i_index) = (p_vout->p_sys->lambda[0][i_plane][i_index] *
1135                                      (*(p_out + i_index))) / ACCURACY +
1136                                      p_vout->p_sys->cstYUV[0][i_plane][i_index];
1137 #else
1138
1139                         *(p_out + i_index) = p_vout->p_sys->LUT[i_plane][p_vout->p_sys->lambda[0][i_plane][i_index]][*(p_out + i_index)];
1140 #endif
1141                     }
1142                     p_out -= LeftOffset;
1143                 }
1144 // end blended zone
1145             }
1146 #endif
1147                 p_in += i_in_pitch;
1148                 p_out += i_out_pitch;
1149             }
1150 #ifdef OVERLAP
1151 // horizontal blend
1152         if (!p_vout->p_sys->b_attenuate)
1153         {
1154             if ((i_row == 0) && (p_vout->p_sys->i_row > 2))
1155             // black bar
1156             {
1157                     int height = 2 * p_vout->p_sys->i_halfHeight / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1158                     TopOffset = i_lines + (2 * p_vout->p_sys->i_halfHeight) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1159                     p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1160                     for (i_index = 0; i_index < height; i_index++)
1161                         for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1162                             *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = constantYUV[i_plane];
1163                     p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1164             }
1165             else if ((i_row + 1 == p_vout->p_sys->i_row) && (p_vout->p_sys->i_row > 2))
1166             // black bar
1167                 {
1168                         int height = 2 * p_vout->p_sys->i_halfHeight / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1169                         TopOffset = height - (2 * p_vout->p_sys->i_halfHeight) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1170                         p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1171                         for (i_index = 0; i_index < height; i_index++)
1172                             for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1173                                 *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = constantYUV[i_plane];
1174                         p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1175                 }
1176         }
1177         else
1178         {
1179             if (p_vout->p_sys->i_row >= 2)
1180             {
1181                 length = 2 * p_vout->p_sys->i_halfHeight / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1182                 if (p_vout->p_sys->b_has_changed)
1183                 {
1184                     Denom = F2(length);
1185                     a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1186                     a_1 = p_vout->p_sys->a_1 * length * (ACCURACY / 100);
1187                     a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1188                    for(i_col_mod = 0; i_col_mod < 2; i_col_mod++)
1189                     for (i_index = 0; i_index < length; i_index++)
1190                     {
1191                         p_vout->p_sys->lambda2[i_col_mod][i_plane][i_index] = CLIP_0A(!i_col_mod ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,length - i_index) + a_0) / Denom);
1192                         p_vout->p_sys->cstYUV2[i_col_mod][i_plane][i_index] = ((ACCURACY - p_vout->p_sys->lambda2[i_col_mod][i_plane][i_index]) * constantYUV[i_plane]) / ACCURACY;
1193                     }
1194                 }
1195 // first blended zone
1196
1197             if (i_row)
1198             {
1199                 TopOffset = i_lines;
1200                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1201                 for (i_index = 0; i_index < length; i_index++)
1202                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1203 #ifndef GAMMA
1204                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = (p_vout->p_sys->lambda2[1][i_plane][i_index] *
1205                                      (*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2))) / ACCURACY +
1206                                      p_vout->p_sys->cstYUV2[1][i_plane][i_index];
1207 #else
1208
1209                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = p_vout->p_sys->LUT[i_plane][p_vout->p_sys->lambda2[1][i_plane][i_index]][*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2)];
1210 #endif
1211                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1212             }
1213             else if (p_vout->p_sys->i_row > 2)
1214             // black bar
1215             {
1216                 TopOffset = i_lines + (2 * p_vout->p_sys->i_halfHeight) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1217                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1218                 for (i_index = 0; i_index < length; i_index++)
1219                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1220                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = constantYUV[i_plane];
1221                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1222             }
1223
1224 // second blended zone
1225
1226             if (i_row + 1 < p_vout->p_sys->i_row)
1227             {
1228                 TopOffset = length;
1229                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1230                 for (i_index = 0; i_index < length; i_index++)
1231                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1232 #ifndef GAMMA
1233                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = (p_vout->p_sys->lambda2[0][i_plane][i_index] *
1234                                      (*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2))) / ACCURACY +
1235                                      p_vout->p_sys->cstYUV2[0][i_plane][i_index];
1236 #else
1237
1238                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = p_vout->p_sys->LUT[i_plane][p_vout->p_sys->lambda2[0][i_plane][i_index]][*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2)];
1239
1240 #endif
1241                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1242             }
1243             else if (p_vout->p_sys->i_row > 2)
1244             // black bar
1245             {
1246                 TopOffset = length - (2 * p_vout->p_sys->i_halfHeight) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1247                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1248                 for (i_index = 0; i_index < length; i_index++)
1249                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1250                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = constantYUV[i_plane];
1251                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1252             }
1253 // end blended zone
1254             }
1255         }
1256 #endif
1257 // bug for wall filter : fix by CC
1258 //            pi_left_skip[i_plane] += i_out_pitch;
1259             pi_left_skip[i_plane] += i_copy_pitch;
1260             }
1261
1262             vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1263                                 p_outpic );
1264             vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1265                                  p_outpic );
1266             i_vout++;
1267         }
1268
1269         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1270                 {
1271                     pi_top_skip[i_plane] += p_vout->p_sys->pp_vout[ i_vout ].i_height
1272                                              * p_pic->p[i_plane].i_lines
1273                                              / p_vout->output.i_height
1274                                              * p_pic->p[i_plane].i_pitch;
1275                 }
1276
1277     }
1278 #ifdef OVERLAP
1279     if (p_vout->p_sys->b_has_changed) p_vout->p_sys->b_has_changed = VLC_FALSE;
1280 #endif
1281 }
1282
1283
1284 /*****************************************************************************
1285  * RenderPackedRGB: displays previously rendered output
1286  *****************************************************************************
1287  * This function send the currently rendered image to Wall image, waits
1288  * until it is displayed and switch the two rendering buffers, preparing next
1289  * frame.
1290  *****************************************************************************/
1291 static void RenderPackedRGB( vout_thread_t *p_vout, picture_t *p_pic )
1292 {
1293     picture_t *p_outpic = NULL;
1294     int i_col, i_row, i_vout, i_plane;
1295     int pi_left_skip[VOUT_MAX_PLANES], pi_top_skip[VOUT_MAX_PLANES];
1296 #ifdef OVERLAP
1297     int LeftOffset, TopOffset;
1298     int Denom;
1299     int a_2;
1300     int a_1;
1301     int a_0;
1302     int i_index, i_index2;
1303 #endif
1304
1305     i_vout = 0;
1306
1307     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1308     {
1309         pi_top_skip[i_plane] = 0;
1310     }
1311
1312     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
1313     {
1314         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1315         {
1316             pi_left_skip[i_plane] = 0;
1317         }
1318
1319         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
1320         {
1321             if( !p_vout->p_sys->pp_vout[ i_vout ].b_active )
1322             {
1323                 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1324                 {
1325                     pi_left_skip[i_plane] +=
1326                         p_vout->p_sys->pp_vout[ i_vout ].i_width * p_pic->p->i_pixel_pitch;
1327                 }
1328                 i_vout++;
1329                 continue;
1330             }
1331
1332             while( ( p_outpic =
1333                 vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1334                                     0, 0, 0 )
1335                    ) == NULL )
1336             {
1337                 if( p_vout->b_die || p_vout->b_error )
1338                 {
1339                     vout_DestroyPicture(
1340                         p_vout->p_sys->pp_vout[ i_vout ].p_vout, p_outpic );
1341                     return;
1342                 }
1343
1344                 msleep( VOUT_OUTMEM_SLEEP );
1345             }
1346
1347             vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1348                               p_outpic, p_pic->date );
1349             vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1350                               p_outpic );
1351
1352             for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1353             {
1354                 uint8_t *p_in, *p_in_end, *p_out;
1355                 int i_in_pitch = p_pic->p[i_plane].i_pitch;
1356                 int i_out_pitch = p_outpic->p[i_plane].i_pitch;
1357                 int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
1358
1359 #ifdef OVERLAP
1360                 if (i_col) pi_left_skip[i_plane] -= (2 * p_vout->p_sys->i_halfLength) * p_pic->p->i_pixel_pitch;
1361                 if ((i_row) && (!i_col)) pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * p_pic->p[i_plane].i_pitch);
1362                 if ((!p_vout->p_sys->pp_vout[p_vout->p_sys->i_col].b_active))
1363                     pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * i_row * p_pic->p[i_plane].i_pitch);
1364 // i_n : previous inactive pp_vout
1365                 int i_n=0;
1366                 while ((!p_vout->p_sys->pp_vout[i_row * p_vout->p_sys->i_col + i_col - 1 - i_n].b_active) && (i_col - i_n > 1)) i_n++;
1367                 if ((i_col > 1) && i_n)
1368                     pi_left_skip[i_plane] -= i_n*(2 * p_vout->p_sys->i_halfLength ) * p_pic->p->i_pixel_pitch;
1369
1370                 p_in = p_pic->p[i_plane].p_pixels
1371                 /* Wall proprities */
1372                 + pi_top_skip[i_plane] + pi_left_skip[i_plane];
1373
1374                 int i_lines = p_outpic->p[i_plane].i_visible_lines;
1375 // 1088 lines bug in a mpeg2 stream of 1080 lines
1376                 if ((p_vout->p_sys->i_row - 1 == i_row) &&
1377                     (p_pic->p[i_plane].i_lines == 1088))
1378                         i_lines -= 8;
1379
1380                 p_in_end = p_in + i_lines * p_pic->p[i_plane].i_pitch;
1381 #else
1382                 p_in = p_pic->p[i_plane].p_pixels
1383                         + pi_top_skip[i_plane] + pi_left_skip[i_plane];
1384
1385                 p_in_end = p_in + p_outpic->p[i_plane].i_visible_lines
1386                                         * p_pic->p[i_plane].i_pitch;
1387 #endif //OVERLAP
1388
1389                 p_out = p_outpic->p[i_plane].p_pixels;
1390
1391
1392 #ifdef OVERLAP
1393         if ((p_vout->p_sys->i_row > 2) && (!i_row))
1394             p_out += (p_outpic->p[i_plane].i_pitch * (2 * p_vout->p_sys->i_halfHeight) * p_pic->p->i_pixel_pitch);
1395
1396         int length;
1397         length = 2 * p_vout->p_sys->i_halfLength * p_pic->p->i_pixel_pitch;
1398
1399         if (p_vout->p_sys->b_has_changed)
1400         {
1401             int i_plane_;
1402             int i_col_mod;
1403             Denom = F2(length / p_pic->p->i_pixel_pitch);
1404             a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1405             a_1 = p_vout->p_sys->a_1 * 2 * p_vout->p_sys->i_halfLength * (ACCURACY / 100);
1406             a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1407             for(i_col_mod = 0; i_col_mod < 2; i_col_mod++)
1408                 for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index++)
1409                     for (i_plane_ =  0; i_plane_ < p_pic->p->i_pixel_pitch; i_plane_++)
1410                         p_vout->p_sys->lambda[i_col_mod][i_plane_][i_index] = CLIP_0A(!i_col_mod ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1411         }
1412 #endif
1413             while( p_in < p_in_end )
1414             {
1415 #ifndef OVERLAP
1416                 p_vout->p_libvlc->pf_memcpy( p_out, p_in, i_copy_pitch);
1417 #else
1418                 if (p_vout->p_sys->i_col > 2)
1419                 {
1420                     // vertical blend
1421                     length /= 2;
1422                     if (i_col == 0)
1423                         p_vout->p_libvlc->pf_memcpy( p_out + length, p_in, i_copy_pitch - length);
1424                     else if (i_col + 1 == p_vout->p_sys->i_col)
1425                             p_vout->p_libvlc->pf_memcpy( p_out, p_in - length, i_copy_pitch - length);
1426                          else
1427                             p_vout->p_libvlc->pf_memcpy( p_out, p_in - length, i_copy_pitch);
1428
1429                     if ((i_col == 0))
1430                     // black bar
1431                     {
1432                         LeftOffset = 0;
1433                         p_out += LeftOffset;
1434                         p_in += LeftOffset;
1435                         for (i_index = 0; i_index < length; i_index++)
1436                                 *(p_out + i_index) = 0;
1437                         p_out -= LeftOffset;
1438                         p_in -= LeftOffset;
1439                     }
1440                     else if ((i_col + 1 == p_vout->p_sys->i_col ))
1441                     // black bar
1442                         {
1443                             LeftOffset = i_copy_pitch - length;
1444                             p_out += LeftOffset;
1445                             p_in += LeftOffset;
1446                             for (i_index = 0; i_index < length; i_index++)
1447                                     *(p_out + i_index) = 0;
1448                             p_out -= LeftOffset;
1449                             p_in -= LeftOffset;
1450                         }
1451                     length *= 2;
1452                 }
1453                 else
1454                     p_vout->p_libvlc->pf_memcpy( p_out, p_in, i_copy_pitch);
1455
1456 // vertical blend
1457 // first blended zone
1458             if (i_col)
1459             {
1460                 LeftOffset = 0;
1461                 p_out += LeftOffset;
1462                 for (i_index = 0; i_index < length; i_index++)
1463 #ifndef GAMMA
1464                     *(p_out + i_index) = (p_vout->p_sys->lambda[1][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch] *
1465                                  (*(p_out + i_index))) / ACCURACY;
1466 #else
1467                     *(p_out + i_index) = p_vout->p_sys->LUT[i_index % p_pic->p->i_pixel_pitch][p_vout->p_sys->lambda[1][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch]][*(p_out + i_index)];
1468 #endif
1469                 p_out -= LeftOffset;
1470             }
1471 // second blended zone
1472             if (i_col + 1 < p_vout->p_sys->i_col)
1473             {
1474                 LeftOffset = i_copy_pitch - length;
1475                 p_out +=  LeftOffset;
1476                 for (i_index = 0; i_index < length; i_index++)
1477 #ifndef GAMMA
1478                     *(p_out + i_index) = (p_vout->p_sys->lambda[0][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch] *
1479                                  (*(p_out + i_index))) / ACCURACY;
1480 #else
1481                     *(p_out + i_index) = p_vout->p_sys->LUT[i_index % p_pic->p->i_pixel_pitch][p_vout->p_sys->lambda[0][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch]][*(p_out + i_index)];
1482 #endif
1483                 p_out -= LeftOffset;
1484             }
1485 // end blended zone
1486 #endif //OVERLAP
1487                 p_in += i_in_pitch;
1488                 p_out += i_out_pitch;
1489             }
1490 #ifdef OVERLAP
1491 // horizontal blend
1492         if (!p_vout->p_sys->b_attenuate)
1493         {
1494             if ((i_row == 0) && (p_vout->p_sys->i_row > 2))
1495             // black bar
1496             {
1497                     TopOffset = i_lines + (2 * p_vout->p_sys->i_halfHeight);
1498                     p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1499                     for (i_index = 0; i_index < length; i_index++)
1500                         for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1501                             *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = 0;
1502                     p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1503             }
1504             else if ((i_row + 1 == p_vout->p_sys->i_row) && (p_vout->p_sys->i_row > 2))
1505             // black bar
1506                 {
1507                     TopOffset = length - (2 * p_vout->p_sys->i_halfHeight);
1508                     p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1509                     for (i_index = 0; i_index < length; i_index++)
1510                         for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1511                             *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = 0;
1512                     p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1513                 }
1514         }
1515         else
1516         {
1517             if (p_vout->p_sys->i_row >= 2)
1518             {
1519                 length = 2 * p_vout->p_sys->i_halfHeight;
1520                 if (p_vout->p_sys->b_has_changed)
1521                 {
1522                     int i_plane_;
1523                     int i_row_mod;
1524                     Denom = F2(length);
1525                     a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1526                     a_1 = p_vout->p_sys->a_1 * length * (ACCURACY / 100);
1527                     a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1528                     for(i_row_mod = 0; i_row_mod < 2; i_row_mod++)
1529                       for (i_index = 0; i_index < length; i_index++)
1530                         for (i_plane_ =  0; i_plane_ < p_pic->p->i_pixel_pitch; i_plane_++)
1531                             p_vout->p_sys->lambda2[i_row_mod][i_plane_][i_index] = CLIP_0A(!i_row_mod ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length) - i_index) + a_0) / Denom);
1532                 }
1533 // first blended zone
1534
1535             if (i_row)
1536             {
1537                 TopOffset = i_lines;
1538                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1539                 for (i_index = 0; i_index < length; i_index++)
1540                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1541 #ifndef GAMMA
1542                     *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = (p_vout->p_sys->lambda2[1][i_index2 % p_pic->p->i_pixel_pitch][i_index] *
1543                                  (*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2))) / ACCURACY;
1544 #else
1545                     *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = p_vout->p_sys->LUT[i_index2 % p_pic->p->i_pixel_pitch][p_vout->p_sys->lambda2[1][i_index2 % p_pic->p->i_pixel_pitch][i_index]][*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2)];
1546 #endif
1547                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1548             }
1549             else if (p_vout->p_sys->i_row > 2)
1550             // black bar
1551             {
1552                 TopOffset = i_lines + (2 * p_vout->p_sys->i_halfHeight);
1553                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1554                 for (i_index = 0; i_index < length; i_index++)
1555                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1556                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = 0;
1557                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1558             }
1559
1560 // second blended zone
1561
1562             if (i_row + 1 < p_vout->p_sys->i_row)
1563             {
1564                 TopOffset = length;
1565                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1566                 for (i_index = 0; i_index < length; i_index++)
1567                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1568 #ifndef GAMMA
1569                     *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = (p_vout->p_sys->lambda2[0][i_index2 % p_pic->p->i_pixel_pitch][i_index] *
1570                                  (*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2))) / ACCURACY;
1571 #else
1572                     *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = p_vout->p_sys->LUT[i_index2 % p_pic->p->i_pixel_pitch][p_vout->p_sys->lambda2[0][i_index2 % p_pic->p->i_pixel_pitch][i_index]][*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2)];
1573
1574 #endif
1575                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1576             }
1577             else if (p_vout->p_sys->i_row > 2)
1578             // black bar
1579             {
1580                 TopOffset = length - (2 * p_vout->p_sys->i_halfHeight);
1581                 p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1582                 for (i_index = 0; i_index < length; i_index++)
1583                     for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1584                         *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = 0;
1585                 p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1586             }
1587 // end blended zone
1588             }
1589         }
1590 #endif
1591 // bug for wall filter : fix by CC
1592 //            pi_left_skip[i_plane] += i_out_pitch;
1593             pi_left_skip[i_plane] += i_copy_pitch;
1594             }
1595
1596             vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1597                                 p_outpic );
1598             vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1599                                  p_outpic );
1600             i_vout++;
1601         }
1602
1603         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1604         {
1605             pi_top_skip[i_plane] += p_vout->p_sys->pp_vout[ i_vout ].i_height
1606                                      * p_pic->p[i_plane].i_lines
1607                                      / p_vout->output.i_height
1608                                      * p_pic->p[i_plane].i_pitch;
1609         }
1610     }
1611 #ifdef OVERLAP
1612     if (p_vout->p_sys->b_has_changed) p_vout->p_sys->b_has_changed = VLC_FALSE;
1613 #endif
1614 }
1615
1616
1617 #ifdef PACKED_YUV
1618 // WARNING : NO DEBUGGED
1619 /*****************************************************************************
1620  * RenderPackedYUV: displays previously rendered output
1621  *****************************************************************************
1622  * This function send the currently rendered image to Wall image, waits
1623  * until it is displayed and switch the two rendering buffers, preparing next
1624  * frame.
1625  *****************************************************************************/
1626 static void RenderPackedYUV( vout_thread_t *p_vout, picture_t *p_pic )
1627 {
1628     picture_t *p_outpic = NULL;
1629     int i_col, i_row, i_vout, i_plane;
1630     int pi_left_skip[VOUT_MAX_PLANES], pi_top_skip[VOUT_MAX_PLANES];
1631 #ifdef OVERLAP
1632     int LeftOffset, TopOffset;
1633     int constantYUV[3] = {0,128,128};
1634     int Denom;
1635     int a_2;
1636     int a_1;
1637     int a_0;
1638     int i_index, i_index2;
1639 #endif
1640
1641
1642     i_vout = 0;
1643
1644     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1645     {
1646         pi_top_skip[i_plane] = 0;
1647     }
1648
1649     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
1650     {
1651         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1652         {
1653             pi_left_skip[i_plane] = 0;
1654         }
1655
1656         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
1657         {
1658             if( !p_vout->p_sys->pp_vout[ i_vout ].b_active )
1659             {
1660                 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1661                 {
1662                     pi_left_skip[i_plane] +=
1663                         p_vout->p_sys->pp_vout[ i_vout ].i_width
1664                          * p_pic->p[i_plane].i_pitch / p_vout->output.i_width;
1665                 }
1666                 i_vout++;
1667                 continue;
1668             }
1669
1670             while( ( p_outpic =
1671                 vout_CreatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1672                                     0, 0, 0 )
1673                    ) == NULL )
1674             {
1675                 if( p_vout->b_die || p_vout->b_error )
1676                 {
1677                     vout_DestroyPicture(
1678                         p_vout->p_sys->pp_vout[ i_vout ].p_vout, p_outpic );
1679                     return;
1680                 }
1681
1682                 msleep( VOUT_OUTMEM_SLEEP );
1683             }
1684
1685             vout_DatePicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1686                               p_outpic, p_pic->date );
1687             vout_LinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1688                               p_outpic );
1689
1690             for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1691             {
1692                 uint8_t *p_in, *p_in_end, *p_out;
1693                 int i_in_pitch = p_pic->p[i_plane].i_pitch;
1694                 int i_out_pitch = p_outpic->p[i_plane].i_pitch;
1695                 int i_copy_pitch = p_outpic->p[i_plane].i_visible_pitch;
1696
1697 #ifdef OVERLAP
1698                 if (i_col) pi_left_skip[i_plane] -= (2 * p_vout->p_sys->i_halfLength ) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1699                 if ((i_row) && (!i_col)) pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * p_pic->p[i_plane].i_pitch) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1700                 if ((p_vout->p_sys->i_row > 2) && (i_row == 1) && (!i_col)) pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * p_pic->p[i_plane].i_pitch) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1701                 if ((!p_vout->p_sys->pp_vout[p_vout->p_sys->i_col].b_active))
1702                     pi_top_skip[i_plane] -= (2 * p_vout->p_sys->i_halfHeight * i_row * p_pic->p[i_plane].i_pitch) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1703 // i_n : previous inactive pp_vout
1704                 int i_n=0;
1705                 while ((!p_vout->p_sys->pp_vout[i_row * p_vout->p_sys->i_col + i_col - 1 - i_n].b_active) && (i_col - i_n > 1)) i_n++;
1706                 if ((i_col > 1) && i_n)
1707                     pi_left_skip[i_plane] -= i_n*(2 * p_vout->p_sys->i_halfLength ) / (p_vout->p_sys->pp_vout[i_vout].i_width / i_copy_pitch);
1708
1709                 p_in = p_pic->p[i_plane].p_pixels
1710                 /* Wall proprities */
1711                 + pi_top_skip[i_plane] + pi_left_skip[i_plane];
1712
1713                 int i_lines = p_outpic->p[i_plane].i_visible_lines;
1714 // 1088 lines bug in a mpeg2 stream of 1080 lines
1715                 if ((p_vout->p_sys->i_row - 1 == i_row) &&
1716                     (p_pic->p[i_plane].i_lines == 1088))
1717                         i_lines -= 8;
1718
1719                 p_in_end = p_in + i_lines * p_pic->p[i_plane].i_pitch;
1720 #else
1721                 p_in = p_pic->p[i_plane].p_pixels
1722                         + pi_top_skip[i_plane] + pi_left_skip[i_plane];
1723
1724                 p_in_end = p_in + p_outpic->p[i_plane].i_visible_lines
1725                                         * p_pic->p[i_plane].i_pitch;
1726 #endif
1727                 p_out = p_outpic->p[i_plane].p_pixels;
1728 #ifdef OVERLAP
1729         int length;
1730         length = 2 * p_vout->p_sys->i_halfLength * p_pic->p->i_pixel_pitch;
1731         LeftOffset = (i_col ? 0 : i_copy_pitch - length);
1732         if (p_vout->p_sys->b_has_changed)
1733         {
1734 #ifdef GAMMA
1735             int i_plane_;
1736             for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index++)
1737                 for (i_plane_ =  0; i_plane_ < p_pic->p->i_pixel_pitch; i_plane_++)
1738                     for (i_index2 = 0; i_index2 < 256; i_index2++)
1739                             p_vout->p_sys->LUT[i_plane_][i_index2][i_index] = F(i_index2, (length / p_pic->p->i_pixel_pitch, i_index, p_vout->p_sys->f_gamma[i_plane_]));
1740 #endif
1741             switch (p_vout->output.i_chroma)
1742                 {
1743                     case VLC_FOURCC('Y','U','Y','2'):    // packed by 2
1744                     case VLC_FOURCC('Y','U','N','V'):    // packed by 2
1745                         Denom = F2(length / p_pic->p->i_pixel_pitch);
1746                         a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1747                         a_1 = p_vout->p_sys->a_1 * 2 * p_vout->p_sys->i_halfLength * (ACCURACY / 100);
1748                         a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1749                         for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index+=p_pic->p->i_pixel_pitch)
1750                         // for each macropixel
1751                         {
1752                                 // first image pixel
1753                                 p_vout->p_sys->lambda[i_col][0][i_index] = CLIP_0A(!i_col ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1754                                 p_vout->p_sys->cstYUV[i_col][0][i_index] = ((ACCURACY - p_vout->p_sys->lambda[i_col][0][i_index]) * constantYUV[0]) / ACCURACY;
1755                                 p_vout->p_sys->lambda[i_col][1][i_index] = CLIP_0A(!i_col ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1756                                 p_vout->p_sys->cstYUV[i_col][1][i_index] = ((ACCURACY - p_vout->p_sys->lambda[i_col][1][i_index]) * constantYUV[1]) / ACCURACY;
1757                                 // second image pixel
1758                                 p_vout->p_sys->lambda[i_col][0][i_index + 1] = CLIP_0A(!i_col ? ACCURACY - (F4(a_2, a_1, i_index + 1) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - (i_index + 1)) + a_0) / Denom);
1759                                 p_vout->p_sys->cstYUV[i_col][0][i_index + 1] = ((ACCURACY - p_vout->p_sys->lambda[i_col][0][i_index]) * constantYUV[0]) / ACCURACY;
1760                                 p_vout->p_sys->lambda[i_col][1][i_index + 1] = p_vout->p_sys->lambda[i_col][1][i_index];
1761                                 p_vout->p_sys->cstYUV[i_col][1][i_index + 1] = p_vout->p_sys->cstYUV[i_col][1][i_index];
1762                         }
1763                         break;
1764                     case VLC_FOURCC('U','Y','V','Y'):    // packed by 2
1765                     case VLC_FOURCC('U','Y','N','V'):    // packed by 2
1766                     case VLC_FOURCC('Y','4','2','2'):    // packed by 2
1767                         Denom = F2(length / p_pic->p->i_pixel_pitch);
1768                         a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1769                         a_1 = p_vout->p_sys->a_1 * 2 * p_vout->p_sys->i_halfLength * (ACCURACY / 100);
1770                         a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1771                         for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index+=p_pic->p->i_pixel_pitch)
1772                         // for each macropixel
1773                         {
1774                                 // first image pixel
1775                                 p_vout->p_sys->lambda[i_col][0][i_index] = CLIP_0A(!i_col ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1776                                 p_vout->p_sys->cstYUV[i_col][0][i_index] = ((ACCURACY - p_vout->p_sys->lambda[i_col][0][i_index]) * constantYUV[1]) / ACCURACY;
1777                                 p_vout->p_sys->lambda[i_col][1][i_index] = CLIP_0A(!i_col ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1778                                 p_vout->p_sys->cstYUV[i_col][1][i_index] = ((ACCURACY - p_vout->p_sys->lambda[i_col][1][i_index]) * constantYUV[0]) / ACCURACY;
1779                                 // second image pixel
1780                                 p_vout->p_sys->lambda[i_col][0][i_index + 1] = CLIP_0A(!i_col ? ACCURACY - (F4(a_2, a_1, i_index + 1) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - (i_index + 1)) + a_0) / Denom);
1781                                 p_vout->p_sys->cstYUV[i_col][0][i_index + 1] = ((ACCURACY - p_vout->p_sys->lambda[i_col][0][i_index]) * constantYUV[1]) / ACCURACY;
1782                                 p_vout->p_sys->lambda[i_col][1][i_index + 1] = p_vout->p_sys->lambda[i_col][1][i_index];
1783                                 p_vout->p_sys->cstYUV[i_col][1][i_index + 1] = p_vout->p_sys->cstYUV[i_col][1][i_index];
1784                         }
1785                         break;
1786                     default :
1787                         break;
1788                 }
1789         }
1790 #endif
1791             while( p_in < p_in_end )
1792             {
1793 #ifndef OVERLAP
1794                 p_vout->p_libvlc->pf_memcpy( p_out, p_in, i_copy_pitch);
1795 #else
1796                 p_vout->p_libvlc->pf_memcpy( p_out + i_col * length, p_in + i_col * length, i_copy_pitch - length);
1797                 p_out += LeftOffset;
1798                 p_in += LeftOffset;
1799 #ifndef GAMMA
1800                 for (i_index = 0; i_index < length; i_index++)
1801                     *(p_out + i_index) = (p_vout->p_sys->lambda[i_col][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch] *
1802                              (*(p_in + i_index))) / ACCURACY +
1803                              p_vout->p_sys->cstYUV[i_col][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch];
1804 #else
1805                 for (i_index = 0; i_index < length; i_index++)
1806                     *(p_out + i_index) = p_vout->p_sys->LUT[i_index % p_pic->p->i_pixel_pitch][(p_vout->p_sys->lambda[i_col][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch] *
1807                              (*(p_in + i_index))) / ACCURACY +
1808                              p_vout->p_sys->cstYUV[i_col][i_index % p_pic->p->i_pixel_pitch][i_index / p_pic->p->i_pixel_pitch]][i_index / p_pic->p->i_pixel_pitch];
1809 #endif
1810                 p_out -= LeftOffset;
1811                 p_in -= LeftOffset;
1812 #endif
1813                 p_in += i_in_pitch;
1814                 p_out += i_out_pitch;
1815             }
1816 #ifdef OVERLAP
1817             if (p_vout->p_sys->i_row == 2)
1818             {
1819                         length = 2 * p_vout->p_sys->i_halfHeight * p_pic->p->i_pixel_pitch;
1820                         TopOffset = (i_row ? i_lines : length / p_pic->p->i_pixel_pitch);
1821                         if (p_vout->p_sys->b_has_changed)
1822                         {
1823 #ifdef GAMMA
1824                                 int i_plane_;
1825                                 for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index++)
1826                                     for (i_plane_ =  0; i_plane_ < p_pic->p->i_pixel_pitch; i_plane_++)
1827                                         for (i_index2 = 0; i_index2 < 256; i_index2++)
1828                                                 p_vout->p_sys->LUT2[i_plane_][i_index2][i_index] = F(i_index2, (length / p_pic->p->i_pixel_pitch, i_index, p_vout->p_sys->f_gamma[i_plane_]));
1829 #endif
1830                                 switch (p_vout->output.i_chroma)
1831                                 {
1832                                     case VLC_FOURCC('Y','U','Y','2'):    // packed by 2
1833                                     case VLC_FOURCC('Y','U','N','V'):    // packed by 2
1834                                         Denom = F2(length / p_pic->p->i_pixel_pitch);
1835                                         a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1836                                         a_1 = p_vout->p_sys->a_1 * 2 * p_vout->p_sys->i_halfHeight * (ACCURACY / 100);
1837                                         a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1838                                         for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index+=p_pic->p->i_pixel_pitch)
1839                                         // for each macropixel
1840                                         {
1841                                                 // first image pixel
1842                                                 p_vout->p_sys->lambda2[i_row][0][i_index] = CLIP_0A(!i_row ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1843                                                 p_vout->p_sys->cstYUV2[i_row][0][i_index] = ((ACCURACY - p_vout->p_sys->lambda2[i_row][0][i_index]) * constantYUV[0]) / ACCURACY;
1844                                                 p_vout->p_sys->lambda2[i_row][1][i_index] = CLIP_0A(!i_row ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1845                                                 p_vout->p_sys->cstYUV2[i_row][1][i_index] = ((ACCURACY - p_vout->p_sys->lambda2[i_row][1][i_index]) * constantYUV[1]) / ACCURACY;
1846                                                 // second image pixel
1847                                                 p_vout->p_sys->lambda2[i_row][0][i_index + 1] = CLIP_0A(!i_row ? ACCURACY - (F4(a_2, a_1, i_index + 1) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - (i_index + 1)) + a_0) / Denom);
1848                                                 p_vout->p_sys->cstYUV2[i_row][0][i_index + 1] = ((ACCURACY - p_vout->p_sys->lambda2[i_row][0][i_index]) * constantYUV[0]) / ACCURACY;
1849                                                 p_vout->p_sys->lambda2[i_row][1][i_index + 1] = p_vout->p_sys->lambda2[i_row][1][i_index];
1850                                                 p_vout->p_sys->cstYUV2[i_row][1][i_index + 1] = p_vout->p_sys->cstYUV2[i_row][1][i_index];
1851                                         }
1852                                         break;
1853                                     case VLC_FOURCC('U','Y','V','Y'):    // packed by 2
1854                                     case VLC_FOURCC('U','Y','N','V'):    // packed by 2
1855                                     case VLC_FOURCC('Y','4','2','2'):    // packed by 2
1856                                         Denom = F2(length / p_pic->p->i_pixel_pitch);
1857                                         a_2 = p_vout->p_sys->a_2 * (ACCURACY / 100);
1858                                         a_1 = p_vout->p_sys->a_1 * 2 * p_vout->p_sys->i_halfHeight * (ACCURACY / 100);
1859                                         a_0 = p_vout->p_sys->a_0 * Denom * (ACCURACY / 100);
1860                                         for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index+=p_pic->p->i_pixel_pitch)
1861                                         // for each macropixel
1862                                         {
1863                                                 // first image pixel
1864                                                 p_vout->p_sys->lambda2[i_row][0][i_index] = CLIP_0A(!i_row ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1865                                                 p_vout->p_sys->cstYUV2[i_row][0][i_index] = ((ACCURACY - p_vout->p_sys->lambda2[i_col][0][i_index]) * constantYUV[1]) / ACCURACY;
1866                                                 p_vout->p_sys->lambda2[i_row][1][i_index] = CLIP_0A(!i_row ? ACCURACY - (F4(a_2, a_1, i_index) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - i_index) + a_0) / Denom);
1867                                                 p_vout->p_sys->cstYUV2[i_row][1][i_index] = ((ACCURACY - p_vout->p_sys->lambda2[i_row][1][i_index]) * constantYUV[0]) / ACCURACY;
1868                                                 // second image pixel
1869                                                 p_vout->p_sys->lambda2[i_row][0][i_index + 1] = CLIP_0A(!i_row ? ACCURACY - (F4(a_2, a_1, i_index + 1) + a_0) / Denom : ACCURACY - (F4(a_2, a_1,(length / p_pic->p->i_pixel_pitch) - (i_index + 1)) + a_0) / Denom);
1870                                                 p_vout->p_sys->cstYUV2[i_row][0][i_index + 1] = ((ACCURACY - p_vout->p_sys->lambda2[i_row][0][i_index]) * constantYUV[1]) / ACCURACY;
1871                                                 p_vout->p_sys->lambda2[i_row][1][i_index + 1] = p_vout->p_sys->lambda2[i_row][1][i_index];
1872                                                 p_vout->p_sys->cstYUV2[i_row][1][i_index + 1] = p_vout->p_sys->cstYUV2[i_row][1][i_index];
1873                                         }
1874                                         break;
1875                                     default :
1876                                         break;
1877                                 }
1878                         }
1879                         p_out -= TopOffset * p_outpic->p[i_plane].i_pitch;
1880 #ifndef GAMMA
1881                         for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index++)
1882                             for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1883                                 *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = (p_vout->p_sys->lambda2[i_row][i_index2 % p_pic->p->i_pixel_pitch][i_index] *
1884                                      (*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2))) / ACCURACY +
1885                                      p_vout->p_sys->cstYUV2[i_row][i_index2 % p_pic->p->i_pixel_pitch][i_index];
1886 #else
1887                         for (i_index = 0; i_index < length / p_pic->p->i_pixel_pitch; i_index++)
1888                             for (i_index2 = 0; i_index2 < i_copy_pitch; i_index2++)
1889                                 *(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2) = p_vout->p_sys->LUT[i_index % p_pic->p->i_pixel_pitch][(p_vout->p_sys->lambda2[i_row][i_index2 % p_pic->p->i_pixel_pitch][i_index] *
1890                                      (*(p_out + (i_index * p_outpic->p[i_plane].i_pitch) + i_index2))) / ACCURACY +
1891                                      p_vout->p_sys->cstYUV2[i_row][i_index2 % p_pic->p->i_pixel_pitch][i_index]][i_index / p_pic->p->i_pixel_pitch];
1892
1893 #endif
1894                         p_out += TopOffset * p_outpic->p[i_plane].i_pitch;
1895             }
1896 #endif
1897 // bug for wall filter : fix by CC
1898 //            pi_left_skip[i_plane] += i_out_pitch;
1899             pi_left_skip[i_plane] += i_copy_pitch;
1900             }
1901
1902             vout_UnlinkPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1903                                 p_outpic );
1904             vout_DisplayPicture( p_vout->p_sys->pp_vout[ i_vout ].p_vout,
1905                                  p_outpic );
1906             i_vout++;
1907         }
1908
1909         for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
1910         {
1911             pi_top_skip[i_plane] += p_vout->p_sys->pp_vout[ i_vout ].i_height
1912                                      * p_pic->p[i_plane].i_lines
1913                                      / p_vout->output.i_height
1914                                      * p_pic->p[i_plane].i_pitch;
1915         }
1916     }
1917 #ifdef OVERLAP
1918     if (p_vout->p_sys->b_has_changed) p_vout->p_sys->b_has_changed = VLC_FALSE;
1919 #endif
1920 }
1921 #endif
1922
1923
1924 /*****************************************************************************
1925  * RemoveAllVout: destroy all the child video output threads
1926  *****************************************************************************/
1927 static void RemoveAllVout( vout_thread_t *p_vout )
1928 {
1929     while( p_vout->p_sys->i_vout )
1930     {
1931          --p_vout->p_sys->i_vout;
1932          if( p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].b_active )
1933          {
1934              DEL_CALLBACKS(
1935                  p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout,
1936                  SendEvents );
1937              vlc_object_detach(
1938                  p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout );
1939              vout_Destroy(
1940                  p_vout->p_sys->pp_vout[ p_vout->p_sys->i_vout ].p_vout );
1941          }
1942     }
1943 }
1944
1945 /*****************************************************************************
1946  * SendEvents: forward mouse and keyboard events to the parent p_vout
1947  *****************************************************************************/
1948 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
1949                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
1950 {
1951     vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
1952     int i_vout;
1953     vlc_value_t sentval = newval;
1954
1955     /* Find the video output index */
1956     for( i_vout = 0; i_vout < p_vout->p_sys->i_vout; i_vout++ )
1957     {
1958         if( p_this == (vlc_object_t *)p_vout->p_sys->pp_vout[ i_vout ].p_vout )
1959         {
1960             break;
1961         }
1962     }
1963
1964     if( i_vout == p_vout->p_sys->i_vout )
1965     {
1966         return VLC_EGENERIC;
1967     }
1968
1969     /* Translate the mouse coordinates */
1970     if( !strcmp( psz_var, "mouse-x" ) )
1971     {
1972 #ifdef OVERLAP
1973         int i_overlap = ((p_vout->p_sys->i_col > 2) ? 0 : 2 * p_vout->p_sys->i_halfLength);
1974            sentval.i_int += (p_vout->output.i_width - i_overlap)
1975 #else
1976            sentval.i_int += p_vout->output.i_width
1977 #endif
1978                          * (i_vout % p_vout->p_sys->i_col)
1979                           / p_vout->p_sys->i_col;
1980     }
1981     else if( !strcmp( psz_var, "mouse-y" ) )
1982     {
1983 #ifdef OVERLAP
1984         int i_overlap = ((p_vout->p_sys->i_row > 2) ? 0 : 2 * p_vout->p_sys->i_halfHeight);
1985            sentval.i_int += (p_vout->output.i_height - i_overlap)
1986 #else
1987            sentval.i_int += p_vout->output.i_height
1988 #endif
1989 //bug fix in Wall plug-in
1990 //                         * (i_vout / p_vout->p_sys->i_row)
1991                          * (i_vout / p_vout->p_sys->i_col)
1992                           / p_vout->p_sys->i_row;
1993     }
1994
1995     var_Set( p_vout, psz_var, sentval );
1996
1997     return VLC_SUCCESS;
1998 }
1999
2000 /*****************************************************************************
2001  * SendEventsToChild: forward events to the child/children vout
2002  *****************************************************************************/
2003 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
2004                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
2005 {
2006
2007     vout_thread_t *p_vout = (vout_thread_t *)p_this;
2008     int i_row, i_col, i_vout = 0;
2009
2010     for( i_row = 0; i_row < p_vout->p_sys->i_row; i_row++ )
2011     {
2012         for( i_col = 0; i_col < p_vout->p_sys->i_col; i_col++ )
2013         {
2014             var_Set( p_vout->p_sys->pp_vout[ i_vout ].p_vout, psz_var, newval);
2015             if( !strcmp( psz_var, "fullscreen" ) ) break;
2016             i_vout++;
2017         }
2018     }
2019
2020     return VLC_SUCCESS;
2021 }