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