]> git.sesse.net Git - vlc/blob - modules/video_filter/extract.c
update module LIST file.
[vlc] / modules / video_filter / extract.c
1 /*****************************************************************************
2  * extract.c : Extract RGB components
3  *****************************************************************************
4  * Copyright (C) 2000-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea .t videolan d@t org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc/vlc.h>
33 #include <vlc_vout.h>
34
35 #include "vlc_filter.h"
36 #include "filter_picture.h"
37
38 #include "math.h"
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static int  Create      ( vlc_object_t * );
44 static void Destroy     ( vlc_object_t * );
45
46 static picture_t *Filter( filter_t *, picture_t * );
47 static int ExtractCallback( vlc_object_t *, char const *,
48                             vlc_value_t, vlc_value_t, void * );
49
50 static void get_red_from_yuv420( picture_t *, picture_t *, int, int, int );
51 static void get_green_from_yuv420( picture_t *, picture_t *, int, int, int );
52 static void get_blue_from_yuv420( picture_t *, picture_t *, int, int, int );
53 static void get_red_from_yuv422( picture_t *, picture_t *, int, int, int );
54 static void get_green_from_yuv422( picture_t *, picture_t *, int, int, int );
55 static void get_blue_from_yuv422( picture_t *, picture_t *, int, int, int );
56 static void make_projection_matrix( filter_t *, int color, int *matrix );
57 static void get_custom_from_yuv420( picture_t *, picture_t *, int, int, int, int * );
58 static void get_custom_from_yuv422( picture_t *, picture_t *, int, int, int, int * );
59 static void get_custom_from_packedyuv422( picture_t *, picture_t *, int * );
60
61
62 #define COMPONENT_TEXT N_("RGB component to extract")
63 #define COMPONENT_LONGTEXT N_("RGB component to extract. 0 for Red, 1 for Green and 2 for Blue.")
64 #define FILTER_PREFIX "extract-"
65
66 static int pi_component_values[] = { 0xFF0000, 0x00FF00, 0x0000FF };
67 static const char *ppsz_component_descriptions[] = { "Red", "Green", "Blue" };
68
69 /*****************************************************************************
70  * Module descriptor
71  *****************************************************************************/
72 vlc_module_begin();
73     set_description( _("Extract RGB component video filter") );
74     set_shortname( _("Extract" ));
75     set_category( CAT_VIDEO );
76     set_subcategory( SUBCAT_VIDEO_VFILTER );
77     set_capability( "video filter2", 0 );
78     add_shortcut( "extract" );
79
80     add_integer_with_range( FILTER_PREFIX "component", 0xFF0000, 1, 0xFFFFFF,
81                  NULL, COMPONENT_TEXT, COMPONENT_LONGTEXT, VLC_FALSE );
82         change_integer_list( pi_component_values, ppsz_component_descriptions, 0 );
83
84     set_callbacks( Create, Destroy );
85 vlc_module_end();
86
87 static const char *ppsz_filter_options[] = {
88     "component", NULL
89 };
90
91 enum { RED=0xFF0000, GREEN=0x00FF00, BLUE=0x0000FF };
92 struct filter_sys_t
93 {
94     int i_color;
95     int *projection_matrix;
96 };
97
98 /*****************************************************************************
99  * Create
100  *****************************************************************************/
101 static int Create( vlc_object_t *p_this )
102 {
103     filter_t *p_filter = (filter_t *)p_this;
104
105     switch( p_filter->fmt_in.video.i_chroma )
106     {
107         case VLC_FOURCC('I','4','2','0'):
108         case VLC_FOURCC('I','Y','U','V'):
109         case VLC_FOURCC('J','4','2','0'):
110         case VLC_FOURCC('Y','V','1','2'):
111
112         case VLC_FOURCC('I','4','2','2'):
113         case VLC_FOURCC('J','4','2','2'):
114
115         CASE_PACKED_YUV_422
116             break;
117
118         default:
119             /* We only want planar YUV 4:2:0 or 4:2:2 */
120             msg_Err( p_filter, "Unsupported input chroma (%4s)",
121                      (char*)&(p_filter->fmt_in.video.i_chroma) );
122             return VLC_EGENERIC;
123     }
124
125     /* Allocate structure */
126     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
127     if( p_filter->p_sys == NULL )
128     {
129         msg_Err( p_filter, "out of memory" );
130         return VLC_ENOMEM;
131     }
132     p_filter->p_sys->projection_matrix = malloc( 9 * sizeof( int ) );
133     if( !p_filter->p_sys->projection_matrix )
134     {
135         free( p_filter->p_sys );
136         msg_Err( p_filter, "out of memory" );
137         return VLC_ENOMEM;
138     }
139
140     config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
141                        p_filter->p_cfg );
142
143     p_filter->p_sys->i_color = var_CreateGetIntegerCommand( p_filter,
144                                                FILTER_PREFIX "component" );
145     var_AddCallback( p_filter, FILTER_PREFIX "component",
146                      ExtractCallback, p_filter->p_sys );
147
148     /* Matrix won't be used for RED, GREEN or BLUE in planar formats */
149     make_projection_matrix( p_filter, p_filter->p_sys->i_color,
150                             p_filter->p_sys->projection_matrix );
151
152     p_filter->pf_video_filter = Filter;
153
154     return VLC_SUCCESS;
155 }
156
157 /*****************************************************************************
158  * Destroy
159  *****************************************************************************/
160 static void Destroy( vlc_object_t *p_this )
161 {
162     filter_t *p_filter = (filter_t *)p_this;
163
164     free( p_filter->p_sys->projection_matrix );
165     free( p_filter->p_sys );
166 }
167
168 /*****************************************************************************
169  * Render
170  *****************************************************************************/
171 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
172 {
173     picture_t *p_outpic;
174
175     if( !p_pic ) return NULL;
176
177     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
178     if( !p_outpic )
179     {
180         msg_Warn( p_filter, "can't get output picture" );
181         if( p_pic->pf_release )
182             p_pic->pf_release( p_pic );
183         return NULL;
184     }
185
186     switch( p_pic->format.i_chroma )
187     {
188         case VLC_FOURCC('I','4','2','0'):
189         case VLC_FOURCC('I','Y','U','V'):
190         case VLC_FOURCC('J','4','2','0'):
191         case VLC_FOURCC('Y','V','1','2'):
192             switch( p_filter->p_sys->i_color )
193             {
194                 case RED:
195                     get_red_from_yuv420( p_pic, p_outpic,
196                                          Y_PLANE, U_PLANE, V_PLANE );
197                     break;
198                 case GREEN:
199                     get_green_from_yuv420( p_pic, p_outpic,
200                                            Y_PLANE, U_PLANE, V_PLANE );
201                     break;
202                 case BLUE:
203                     get_blue_from_yuv420( p_pic, p_outpic,
204                                           Y_PLANE, U_PLANE, V_PLANE );
205                     break;
206                 default:
207                     get_custom_from_yuv420( p_pic, p_outpic,
208                                             Y_PLANE, U_PLANE, V_PLANE,
209                                             p_filter->p_sys->projection_matrix);
210                     break;
211             }
212             break;
213
214         case VLC_FOURCC('I','4','2','2'):
215         case VLC_FOURCC('J','4','2','2'):
216             switch( p_filter->p_sys->i_color )
217             {
218                 case RED:
219                     get_red_from_yuv422( p_pic, p_outpic,
220                                          Y_PLANE, U_PLANE, V_PLANE );
221                     break;
222                 case GREEN:
223                     get_green_from_yuv422( p_pic, p_outpic,
224                                            Y_PLANE, U_PLANE, V_PLANE );
225                     break;
226                 case BLUE:
227                     get_blue_from_yuv422( p_pic, p_outpic,
228                                           Y_PLANE, U_PLANE, V_PLANE );
229                     break;
230                 default:
231                     get_custom_from_yuv422( p_pic, p_outpic,
232                                             Y_PLANE, U_PLANE, V_PLANE,
233                                             p_filter->p_sys->projection_matrix);
234                     break;
235             }
236             break;
237
238         CASE_PACKED_YUV_422
239             get_custom_from_packedyuv422( p_pic, p_outpic,
240                                           p_filter->p_sys->projection_matrix );
241             break;
242
243         default:
244             msg_Warn( p_filter, "Unsupported input chroma (%4s)",
245                       (char*)&(p_pic->format.i_chroma) );
246             if( p_pic->pf_release )
247                 p_pic->pf_release( p_pic );
248             return NULL;
249     }
250
251     p_outpic->date = p_pic->date;
252     p_outpic->b_force = p_pic->b_force;
253     p_outpic->i_nb_fields = p_pic->i_nb_fields;
254     p_outpic->b_progressive = p_pic->b_progressive;
255     p_outpic->b_top_field_first = p_pic->b_top_field_first;
256
257     if( p_pic->pf_release )
258         p_pic->pf_release( p_pic );
259
260     return p_outpic;
261 }
262
263 static inline uint8_t crop( int a )
264 {
265     if( a < 0 ) return 0;
266     if( a > 255 ) return 255;
267     else return (uint8_t)a;
268 }
269
270 #define U 128
271 #define V 128
272
273 static void mmult( double *res, double *a, double *b )
274 {
275     int i, j, k;
276     for( i = 0; i < 3; i++ )
277     {
278         for( j = 0; j < 3; j++ )
279         {
280             res[ i*3 + j ] = 0.;
281             for( k = 0; k < 3; k++ )
282             {
283                 res[ i*3 + j ] += a[ i*3 + k ] * b[ k*3 + j ];
284             }
285         }
286     }
287 }
288 static void make_projection_matrix( filter_t *p_filter, int color, int *matrix )
289 {
290     double left_matrix[9] =
291         {  76.24500,  149.68500,  29.07000,
292           -43.02765,  -84.47235, 127.50000,
293           127.50000, -106.76534, -20.73466 };
294     double right_matrix[9] =
295         { 257.00392,   0.00000,  360.31950,
296           257.00392, -88.44438, -183.53583,
297           257.00392, 455.41095,    0.00000 };
298     double red = ((double)(( 0xFF0000 & color )>>16))/255.;
299     double green = ((double)(( 0x00FF00 & color )>>8))/255.;
300     double blue = ((double)( 0x0000FF & color ))/255.;
301     double norm = sqrt( red*red + green*green + blue*blue );
302     red /= norm;
303     green /= norm;
304     blue /= norm;
305     /* XXX: We might still need to norm the rgb_matrix */
306     double rgb_matrix[9] =
307         { red*red,    red*green,   red*blue,
308           red*green,  green*green, green*blue,
309           red*blue,   green*blue,  blue*blue };
310     double result1[9];
311     double result[9];
312     int i;
313     msg_Dbg( p_filter, "red: %f", red );
314     msg_Dbg( p_filter, "green: %f", green );
315     msg_Dbg( p_filter, "blue: %f", blue );
316     mmult( result1, rgb_matrix, right_matrix );
317     mmult( result, left_matrix, result1 );
318     for( i = 0; i < 9; i++ )
319     {
320         matrix[i] = (int)result[i];
321     }
322     msg_Dbg( p_filter, "Projection matrix:" );
323     msg_Dbg( p_filter, "%6d %6d %6d", matrix[0], matrix[1], matrix[2] );
324     msg_Dbg( p_filter, "%6d %6d %6d", matrix[3], matrix[4], matrix[5] );
325     msg_Dbg( p_filter, "%6d %6d %6d", matrix[6], matrix[7], matrix[8] );
326 }
327
328 static void get_custom_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
329                                     int yp, int up, int vp, int *m )
330 {
331     uint8_t *y1in = p_inpic->p[yp].p_pixels;
332     uint8_t *y2in;
333     uint8_t *uin  = p_inpic->p[up].p_pixels;
334     uint8_t *vin  = p_inpic->p[vp].p_pixels;
335
336     uint8_t *y1out = p_outpic->p[yp].p_pixels;
337     uint8_t *y2out;
338     uint8_t *uout  = p_outpic->p[up].p_pixels;
339     uint8_t *vout  = p_outpic->p[vp].p_pixels;
340
341     const int i_pitch = p_inpic->p[yp].i_pitch;
342     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
343     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
344
345     const int i_uv_pitch = p_inpic->p[up].i_pitch;
346     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
347
348     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
349     while( y1in < yend )
350     {
351         const uint8_t *y1end = y1in + i_visible_pitch;
352         y2in  = y1in + i_pitch;
353         y2out = y1out + i_pitch;
354         while( y1in < y1end )
355         {
356             *uout++ = crop( (*y1in * m[3] + (*uin-U) * m[4] + (*vin-V) * m[5])
357                       / 65536 + U );
358             *vout++ = crop( (*y1in * m[6] + (*uin-U) * m[7] + (*vin-V) * m[8])
359                       / 65536 + V );
360             *y1out++ = crop( (*y1in++ * m[0] + (*uin-U) * m[1] + (*vin-V) * m[2])
361                        / 65536 );
362             *y1out++ = crop( (*y1in++ * m[0] + (*uin-U) * m[1] + (*vin-V) * m[2])
363                        / 65536 );
364             *y2out++ = crop( (*y2in++ * m[0] + (*uin-U) * m[1] + (*vin-V) * m[2])
365                        / 65536 );
366             *y2out++ = crop( (*y2in++ * m[0] + (*uin++ - U) * m[1] + (*vin++ -V) * m[2])
367                        / 65536 );
368         }
369         y1in  += 2*i_pitch - i_visible_pitch;
370         y1out += 2*i_pitch - i_visible_pitch;
371         uin   += i_uv_pitch - i_uv_visible_pitch;
372         uout  += i_uv_pitch - i_uv_visible_pitch;
373         vin   += i_uv_pitch - i_uv_visible_pitch;
374         vout  += i_uv_pitch - i_uv_visible_pitch;
375     }
376 }
377 static void get_custom_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
378                                     int yp, int up, int vp, int *m )
379 {
380     uint8_t *y1in = p_inpic->p[yp].p_pixels;
381     uint8_t *uin  = p_inpic->p[up].p_pixels;
382     uint8_t *vin  = p_inpic->p[vp].p_pixels;
383
384     uint8_t *y1out = p_outpic->p[yp].p_pixels;
385     uint8_t *uout  = p_outpic->p[up].p_pixels;
386     uint8_t *vout  = p_outpic->p[vp].p_pixels;
387
388     const int i_pitch = p_inpic->p[yp].i_pitch;
389     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
390     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
391
392     const int i_uv_pitch = p_inpic->p[up].i_pitch;
393     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
394
395     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
396     while( y1in < yend )
397     {
398         const uint8_t *y1end = y1in + i_visible_pitch;
399         while( y1in < y1end )
400         {
401             *uout++ = crop( (*y1in * m[3] + (*uin-U) * m[4] + (*vin-V) * m[5])
402                       / 65536 + U );
403             *vout++ = crop( (*y1in * m[6] + (*uin-U) * m[7] + (*vin-V) * m[8])
404                       / 65536 + V );
405             *y1out++ = crop( (*y1in++ * m[0] + (*uin-U) * m[1] + (*vin-V) * m[2])
406                        / 65536 );
407             *y1out++ = crop( (*y1in++ * m[0] + (*uin++ -U) * m[1] + (*vin++ -V) * m[2])
408                        / 65536 );
409         }
410         y1in  += i_pitch - i_visible_pitch;
411         y1out += i_pitch - i_visible_pitch;
412         uin   += i_uv_pitch - i_uv_visible_pitch;
413         uout  += i_uv_pitch - i_uv_visible_pitch;
414         vin   += i_uv_pitch - i_uv_visible_pitch;
415         vout  += i_uv_pitch - i_uv_visible_pitch;
416     }
417 }
418
419 static void get_custom_from_packedyuv422( picture_t *p_inpic,
420                                           picture_t *p_outpic,
421                                           int *m )
422 {
423     int i_y_offset, i_u_offset, i_v_offset;
424     if( GetPackedYuvOffsets( p_inpic->format.i_chroma, &i_y_offset,
425                          &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
426         return;
427
428     uint8_t *yin = p_inpic->p->p_pixels + i_y_offset;
429     uint8_t *uin = p_inpic->p->p_pixels + i_u_offset;
430     uint8_t *vin = p_inpic->p->p_pixels + i_v_offset;
431
432     uint8_t *yout = p_outpic->p->p_pixels + i_y_offset;
433     uint8_t *uout = p_outpic->p->p_pixels + i_u_offset;
434     uint8_t *vout = p_outpic->p->p_pixels + i_v_offset;
435
436     const int i_pitch = p_inpic->p->i_pitch;
437     const int i_visible_pitch = p_inpic->p->i_visible_pitch;
438     const int i_visible_lines = p_inpic->p->i_visible_lines;
439
440     const uint8_t *yend = yin + i_visible_lines * i_pitch;
441     while( yin < yend )
442     {
443         const uint8_t *ylend = yin + i_visible_pitch;
444         while( yin < ylend )
445         {
446             *uout = crop( (*yin * m[3] + (*uin-U) * m[4] + (*vin-V) * m[5])
447                       / 65536 + U );
448             uout += 4;
449             *vout = crop( (*yin * m[6] + (*uin-U) * m[7] + (*vin-V) * m[8])
450                      / 65536 + V );
451             vout += 4;
452             *yout = crop( (*yin * m[0] + (*uin-U) * m[1] + (*vin-V) * m[2])
453                        / 65536 );
454             yin  += 2;
455             yout += 2;
456             *yout = crop( (*yin * m[0] + (*uin-U) * m[1] + (*vin-V) * m[2])
457                        / 65536 );
458             yin  += 2;
459             yout += 2;
460             uin  += 4;
461             vin  += 4;
462         }
463         yin  += i_pitch - i_visible_pitch;
464         yout += i_pitch - i_visible_pitch;
465         uin  += i_pitch - i_visible_pitch;
466         uout += i_pitch - i_visible_pitch;
467         vin  += i_pitch - i_visible_pitch;
468         vout += i_pitch - i_visible_pitch;
469     }
470 }
471
472 static void get_red_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
473                                  int yp, int up, int vp )
474 {
475     uint8_t *y1in = p_inpic->p[yp].p_pixels;
476     uint8_t *y2in;
477     uint8_t *vin  = p_inpic->p[vp].p_pixels;
478
479     uint8_t *y1out = p_outpic->p[yp].p_pixels;
480     uint8_t *y2out;
481     uint8_t *uout  = p_outpic->p[up].p_pixels;
482     uint8_t *vout  = p_outpic->p[vp].p_pixels;
483
484     const int i_pitch = p_inpic->p[yp].i_pitch;
485     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
486     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
487
488     const int i_uv_pitch = p_inpic->p[up].i_pitch;
489     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
490
491     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
492     while( y1in < yend )
493     {
494         const uint8_t *y1end = y1in + i_visible_pitch;
495         y2in  = y1in + i_pitch;
496         y2out = y1out + i_pitch;
497         while( y1in < y1end )
498         {
499 /*
500 19595   0   27473
501 -11058  0   -15504
502 32768   0   45941
503 */
504             *uout++ = crop( (*y1in * -11058 + (*vin - V) * -15504)
505                       / 65536 + U );
506             *vout++ = crop( (*y1in * 32768 + (*vin - V) * 45941)
507                       / 65536 + V );
508             *y1out++ = crop( (*y1in++ * 19595 + (*vin - V) * 27473)
509                        / 65536 );
510             *y1out++ = crop( (*y1in++ * 19595 + (*vin - V) * 27473)
511                        / 65536 );
512             *y2out++ = crop( (*y2in++ * 19594 + (*vin - V) * 27473)
513                        / 65536 );
514             *y2out++ = crop( (*y2in++ * 19594 + (*vin++ - V) * 27473)
515                        / 65536 );
516         }
517         y1in  += 2*i_pitch - i_visible_pitch;
518         y1out += 2*i_pitch - i_visible_pitch;
519         uout  += i_uv_pitch - i_uv_visible_pitch;
520         vin   += i_uv_pitch - i_uv_visible_pitch;
521         vout  += i_uv_pitch - i_uv_visible_pitch;
522     }
523 }
524
525 static void get_green_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
526                                  int yp, int up, int vp )
527 {
528     uint8_t *y1in = p_inpic->p[yp].p_pixels;
529     uint8_t *y2in;
530     uint8_t *uin  = p_inpic->p[up].p_pixels;
531     uint8_t *vin  = p_inpic->p[vp].p_pixels;
532
533     uint8_t *y1out = p_outpic->p[yp].p_pixels;
534     uint8_t *y2out;
535     uint8_t *uout  = p_outpic->p[up].p_pixels;
536     uint8_t *vout  = p_outpic->p[vp].p_pixels;
537
538     const int i_pitch = p_inpic->p[yp].i_pitch;
539     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
540     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
541
542     const int i_uv_pitch = p_inpic->p[up].i_pitch;
543     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
544
545     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
546     while( y1in < yend )
547     {
548         const uint8_t *y1end = y1in + i_visible_pitch;
549         y2in  = y1in + i_pitch;
550         y2out = y1out + i_pitch;
551         while( y1in < y1end )
552         {
553 /*
554 38470   -13239  -27473
555 -21710  7471    15504
556 -27439  9443    19595
557 */
558             *uout++ = crop( (*y1in * -21710 + (*uin-U) * 7471 + (*vin-V) * 15504)
559                       / 65536 + U );
560             *vout++ = crop( (*y1in * -27439 + (*uin-U) * 9443 + (*vin-V) * 19595)
561                       / 65536 + V );
562             *y1out++ = crop( (*y1in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
563                        / 65536 );
564             *y1out++ = crop( (*y1in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
565                        / 65536 );
566             *y2out++ = crop( (*y2in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
567                        / 65536 );
568             *y2out++ = crop( (*y2in++ * 38470 + (*uin++ - U) * -13239 + (*vin++ -V) * -27473)
569                        / 65536 );
570         }
571         y1in  += 2*i_pitch - i_visible_pitch;
572         y1out += 2*i_pitch - i_visible_pitch;
573         uin   += i_uv_pitch - i_uv_visible_pitch;
574         uout  += i_uv_pitch - i_uv_visible_pitch;
575         vin   += i_uv_pitch - i_uv_visible_pitch;
576         vout  += i_uv_pitch - i_uv_visible_pitch;
577     }
578 }
579
580 static void get_blue_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
581                                  int yp, int up, int vp )
582 {
583     uint8_t *y1in = p_inpic->p[yp].p_pixels;
584     uint8_t *y2in;
585     uint8_t *uin  = p_inpic->p[up].p_pixels;
586
587     uint8_t *y1out = p_outpic->p[yp].p_pixels;
588     uint8_t *y2out;
589     uint8_t *uout  = p_outpic->p[up].p_pixels;
590     uint8_t *vout  = p_outpic->p[vp].p_pixels;
591
592     const int i_pitch = p_inpic->p[yp].i_pitch;
593     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
594     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
595
596     const int i_uv_pitch = p_inpic->p[up].i_pitch;
597     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
598
599     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
600     while( y1in < yend )
601     {
602         const uint8_t *y1end = y1in + i_visible_pitch;
603         y2in  = y1in + i_pitch;
604         y2out = y1out + i_pitch;
605         while( y1in < y1end )
606         {
607 /*
608 7471    13239   0
609 32768   58065   0
610 -5329   -9443   0
611 */
612             *uout++ = crop( (*y1in* 32768 + (*uin - U) * 58065 )
613                       / 65536 + U );
614             *vout++ = crop( (*y1in * -5329 + (*uin - U) * -9443 )
615                       / 65536 + V );
616             *y1out++ = crop( (*y1in++ * 7471 + (*uin - U) * 13239 )
617                        / 65536 );
618             *y1out++ = crop( (*y1in++ * 7471 + (*uin - U) * 13239 )
619                        / 65536 );
620             *y2out++ = crop( (*y2in++ * 7471 + (*uin - U) * 13239 )
621                        / 65536 );
622             *y2out++ = crop( (*y2in++ * 7471 + (*uin++ - U) * 13239 )
623                        / 65536 );
624         }
625         y1in  += 2*i_pitch - i_visible_pitch;
626         y1out += 2*i_pitch - i_visible_pitch;
627         uin   += i_uv_pitch - i_uv_visible_pitch;
628         uout  += i_uv_pitch - i_uv_visible_pitch;
629         vout  += i_uv_pitch - i_uv_visible_pitch;
630     }
631 }
632
633 static void get_red_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
634                                  int yp, int up, int vp )
635 {
636     uint8_t *y1in = p_inpic->p[yp].p_pixels;
637     uint8_t *vin  = p_inpic->p[vp].p_pixels;
638
639     uint8_t *y1out = p_outpic->p[yp].p_pixels;
640     uint8_t *uout  = p_outpic->p[up].p_pixels;
641     uint8_t *vout  = p_outpic->p[vp].p_pixels;
642
643     const int i_pitch = p_inpic->p[yp].i_pitch;
644     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
645     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
646
647     const int i_uv_pitch = p_inpic->p[up].i_pitch;
648     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
649
650     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
651     while( y1in < yend )
652     {
653         const uint8_t *y1end = y1in + i_visible_pitch;
654         while( y1in < y1end )
655         {
656 /*
657 19595   0   27473
658 -11058  0   -15504
659 32768   0   45941
660 */
661             *uout++ = crop( (*y1in * -11058 + (*vin - V) * -15504)
662                       / 65536 + U );
663             *vout++ = crop( (*y1in * 32768 + (*vin - V) * 45941)
664                       / 65536 + V );
665             *y1out++ = crop( (*y1in++ * 19595 + (*vin - V) * 27473)
666                        / 65536 );
667             *y1out++ = crop( (*y1in++ * 19595 + (*vin++ - V) * 27473)
668                        / 65536 );
669         }
670         y1in  += i_pitch - i_visible_pitch;
671         y1out += i_pitch - i_visible_pitch;
672         uout  += i_uv_pitch - i_uv_visible_pitch;
673         vin   += i_uv_pitch - i_uv_visible_pitch;
674         vout  += i_uv_pitch - i_uv_visible_pitch;
675     }
676 }
677
678 static void get_green_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
679                                    int yp, int up, int vp )
680 {
681     uint8_t *y1in = p_inpic->p[yp].p_pixels;
682     uint8_t *uin  = p_inpic->p[up].p_pixels;
683     uint8_t *vin  = p_inpic->p[vp].p_pixels;
684
685     uint8_t *y1out = p_outpic->p[yp].p_pixels;
686     uint8_t *uout  = p_outpic->p[up].p_pixels;
687     uint8_t *vout  = p_outpic->p[vp].p_pixels;
688
689     const int i_pitch = p_inpic->p[yp].i_pitch;
690     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
691     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
692
693     const int i_uv_pitch = p_inpic->p[up].i_pitch;
694     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
695
696     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
697     while( y1in < yend )
698     {
699         const uint8_t *y1end = y1in + i_visible_pitch;
700         while( y1in < y1end )
701         {
702 /*
703 38470   -13239  -27473
704 -21710  7471    15504
705 -27439  9443    19595
706 */
707             *uout++ = crop( (*y1in * -21710 + (*uin-U) * 7471 + (*vin-V) * 15504)
708                       / 65536 + U );
709             *vout++ = crop( (*y1in * -27439 + (*uin-U) * 9443 + (*vin-V) * 19595)
710                       / 65536 + V );
711             *y1out++ = crop( (*y1in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
712                        / 65536 );
713             *y1out++ = crop( (*y1in++ * 38470 + (*uin++-U) * -13239 + (*vin++-V) * -27473)
714                        / 65536 );
715         }
716         y1in  += i_pitch - i_visible_pitch;
717         y1out += i_pitch - i_visible_pitch;
718         uin   += i_uv_pitch - i_uv_visible_pitch;
719         uout  += i_uv_pitch - i_uv_visible_pitch;
720         vin   += i_uv_pitch - i_uv_visible_pitch;
721         vout  += i_uv_pitch - i_uv_visible_pitch;
722     }
723 }
724
725 static void get_blue_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
726                                  int yp, int up, int vp )
727 {
728     uint8_t *y1in = p_inpic->p[yp].p_pixels;
729     uint8_t *uin  = p_inpic->p[up].p_pixels;
730
731     uint8_t *y1out = p_outpic->p[yp].p_pixels;
732     uint8_t *uout  = p_outpic->p[up].p_pixels;
733     uint8_t *vout  = p_outpic->p[vp].p_pixels;
734
735     const int i_pitch = p_inpic->p[yp].i_pitch;
736     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
737     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
738
739     const int i_uv_pitch = p_inpic->p[up].i_pitch;
740     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
741
742     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
743     while( y1in < yend )
744     {
745         const uint8_t *y1end = y1in + i_visible_pitch;
746         while( y1in < y1end )
747         {
748 /*
749 7471    13239   0
750 32768   58065   0
751 -5329   -9443   0
752 */
753             *uout++ = crop( (*y1in* 32768 + (*uin - U) * 58065 )
754                       / 65536 + U );
755             *vout++ = crop( (*y1in * -5329 + (*uin - U) * -9443 )
756                       / 65536 + V );
757             *y1out++ = crop( (*y1in++ * 7471 + (*uin - U) * 13239 )
758                        / 65536 );
759             *y1out++ = crop( (*y1in++ * 7471 + (*uin++ - U) * 13239 )
760                        / 65536 );
761         }
762         y1in  += i_pitch - i_visible_pitch;
763         y1out += i_pitch - i_visible_pitch;
764         uin   += i_uv_pitch - i_uv_visible_pitch;
765         uout  += i_uv_pitch - i_uv_visible_pitch;
766         vout  += i_uv_pitch - i_uv_visible_pitch;
767     }
768 }
769
770 static int ExtractCallback( vlc_object_t *p_this, char const *psz_var,
771                             vlc_value_t oldval, vlc_value_t newval,
772                             void *p_data )
773 {
774     VLC_UNUSED(oldval);
775     filter_sys_t *p_sys = (filter_sys_t *)p_data;
776
777     if( !strcmp( psz_var, FILTER_PREFIX "component" ) )
778     {
779         p_sys->i_color = newval.i_int;
780         /* Matrix won't be used for RED, GREEN or BLUE in planar formats */
781         make_projection_matrix( (filter_t *)p_this, p_sys->i_color,
782                                 p_sys->projection_matrix );
783     }
784     else
785     {
786         msg_Warn( p_this, "Unknown callback command." );
787     }
788     return VLC_SUCCESS;
789 }