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