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