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