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