]> git.sesse.net Git - vlc/blob - modules/video_filter/extract.c
* New color extraction video filter. Can be used to extract the Red, Green or Blue...
[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 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_vout.h>
32
33 #include "vlc_filter.h"
34
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38 static int  Create      ( vlc_object_t * );
39 static void Destroy     ( vlc_object_t * );
40
41 static picture_t *Filter( filter_t *, picture_t * );
42
43 #define COMPONENT_TEXT N_("RGB component to extract")
44 #define COMPONENT_LONGTEXT N_("RGB component to extract. 0 for Red, 1 for Green and 2 for Blue.")
45 #define FILTER_PREFIX "extract-"
46
47 static int pi_component_values[] = { 0, 1, 2 };
48 static const char *ppsz_component_descriptions[] = { "Red", "Green", "Blue" };
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 vlc_module_begin();
54     set_description( _("Extract RGB component video filter") );
55     set_shortname( _("Extract" ));
56     set_category( CAT_VIDEO );
57     set_subcategory( SUBCAT_VIDEO_VFILTER );
58     set_capability( "video filter2", 0 );
59     add_shortcut( "extract" );
60
61     add_integer( FILTER_PREFIX "component", 0, NULL,
62                  COMPONENT_TEXT, COMPONENT_LONGTEXT, VLC_FALSE );
63         change_integer_list( pi_component_values, ppsz_component_descriptions, 0 );
64
65     set_callbacks( Create, Destroy );
66 vlc_module_end();
67
68 static const char *ppsz_filter_options[] = {
69     "component", NULL
70 };
71
72 enum { RED, GREEN, BLUE };
73 struct filter_sys_t
74 {
75     int i_color;
76 };
77
78 /*****************************************************************************
79  * Create
80  *****************************************************************************/
81 static int Create( vlc_object_t *p_this )
82 {
83     filter_t *p_filter = (filter_t *)p_this;
84
85     /* Allocate structure */
86     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
87     if( p_filter->p_sys == NULL )
88     {
89         msg_Err( p_filter, "out of memory" );
90         return VLC_ENOMEM;
91     }
92
93     config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
94                        p_filter->p_cfg );
95
96     var_Create( p_filter, FILTER_PREFIX "component",
97                 VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
98     p_filter->p_sys->i_color = var_GetInteger( p_filter,
99                                                FILTER_PREFIX "component" );
100
101     p_filter->pf_video_filter = Filter;
102
103     return VLC_SUCCESS;
104 }
105
106 /*****************************************************************************
107  * Destroy
108  *****************************************************************************/
109 static void Destroy( vlc_object_t *p_this )
110 {
111     filter_t *p_filter = (filter_t *)p_this;
112
113     free( p_filter->p_sys );
114 }
115
116 /*****************************************************************************
117  * Render
118  *****************************************************************************/
119 static void get_red_from_yuv420( picture_t *, picture_t *, int, int, int );
120 static void get_green_from_yuv420( picture_t *, picture_t *, int, int, int );
121 static void get_blue_from_yuv420( picture_t *, picture_t *, int, int, int );
122 static void get_red_from_yuv422( picture_t *, picture_t *, int, int, int );
123 static void get_green_from_yuv422( picture_t *, picture_t *, int, int, int );
124 static void get_blue_from_yuv422( picture_t *, picture_t *, int, int, int );
125
126 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
127 {
128     picture_t *p_outpic;
129
130     if( !p_pic ) return NULL;
131
132     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
133     if( !p_outpic )
134     {
135         msg_Warn( p_filter, "can't get output picture" );
136         if( p_pic->pf_release )
137             p_pic->pf_release( p_pic );
138         return NULL;
139     }
140
141     switch( p_pic->format.i_chroma )
142     {
143         case VLC_FOURCC('I','4','2','0'):
144         case VLC_FOURCC('I','Y','U','V'):
145         case VLC_FOURCC('J','4','2','0'):
146         case VLC_FOURCC('Y','V','1','2'):
147             switch( p_filter->p_sys->i_color )
148             {
149                 case RED:
150                     get_red_from_yuv420( p_pic, p_outpic,
151                                          Y_PLANE, U_PLANE, V_PLANE );
152                     break;
153                 case GREEN:
154                     get_green_from_yuv420( p_pic, p_outpic,
155                                            Y_PLANE, U_PLANE, V_PLANE );
156                     break;
157                 case BLUE:
158                     get_blue_from_yuv420( p_pic, p_outpic,
159                                           Y_PLANE, U_PLANE, V_PLANE );
160                     break;
161             }
162             break;
163
164         case VLC_FOURCC('I','4','2','2'):
165         case VLC_FOURCC('J','4','2','2'):
166             switch( p_filter->p_sys->i_color )
167             {
168                 case RED:
169                     get_red_from_yuv422( p_pic, p_outpic,
170                                          Y_PLANE, U_PLANE, V_PLANE );
171                     break;
172                 case GREEN:
173                     get_green_from_yuv422( p_pic, p_outpic,
174                                            Y_PLANE, U_PLANE, V_PLANE );
175                     break;
176                 case BLUE:
177                     get_blue_from_yuv422( p_pic, p_outpic,
178                                           Y_PLANE, U_PLANE, V_PLANE );
179                     break;
180             }
181             break;
182
183         default:
184             msg_Warn( p_filter, "Unsupported input chroma (%4s)",
185                       (char*)&(p_pic->format.i_chroma) );
186             if( p_pic->pf_release )
187                 p_pic->pf_release( p_pic );
188             return NULL;
189     }
190
191     p_outpic->date = p_pic->date;
192     p_outpic->b_force = p_pic->b_force;
193     p_outpic->i_nb_fields = p_pic->i_nb_fields;
194     p_outpic->b_progressive = p_pic->b_progressive;
195     p_outpic->b_top_field_first = p_pic->b_top_field_first;
196
197     if( p_pic->pf_release )
198         p_pic->pf_release( p_pic );
199
200     return p_outpic;
201 }
202
203 inline uint8_t crop( int a );
204 inline uint8_t crop( int a )
205 {
206     if( a < 0 ) return 0;
207     if( a > 255 ) return 255;
208     else return (uint8_t)a;
209 }
210
211 #define U 128
212 #define V 128
213
214 static void get_red_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
215                                  int yp, int up, int vp )
216 {
217     uint8_t *y1in = p_inpic->p[yp].p_pixels;
218     uint8_t *y2in;
219     uint8_t *vin  = p_inpic->p[vp].p_pixels;
220
221     uint8_t *y1out = p_outpic->p[yp].p_pixels;
222     uint8_t *y2out;
223     uint8_t *uout  = p_outpic->p[up].p_pixels;
224     uint8_t *vout  = p_outpic->p[vp].p_pixels;
225
226     const int i_pitch = p_inpic->p[yp].i_pitch;
227     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
228     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
229
230     const int i_uv_pitch = p_inpic->p[up].i_pitch;
231     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
232
233     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
234     while( y1in < yend )
235     {
236         const uint8_t *y1end = y1in + i_visible_pitch;
237         y2in  = y1in + i_pitch;
238         y2out = y1out + i_pitch;
239         while( y1in < y1end )
240         {
241 /*
242 19595   0   27473
243 -11058  0   -15504
244 32768   0   45941
245 */
246             *uout++ = crop( (*y1in * -11058 + (*vin - V) * -15504)
247                       / 65536 + U );
248             *vout++ = crop( (*y1in * 32768 + (*vin - V) * 45941)
249                       / 65536 + V );
250             *y1out++ = crop( (*y1in++ * 19595 + (*vin - V) * 27473)
251                        / 65536 );
252             *y1out++ = crop( (*y1in++ * 19595 + (*vin - V) * 27473)
253                        / 65536 );
254             *y2out++ = crop( (*y2in++ * 19594 + (*vin - V) * 27473)
255                        / 65536 );
256             *y2out++ = crop( (*y2in++ * 19594 + (*vin++ - V) * 27473)
257                        / 65536 );
258         }
259         y1in  += 2*i_pitch - i_visible_pitch;
260         y1out += 2*i_pitch - i_visible_pitch;
261         uout  += i_uv_pitch - i_uv_visible_pitch;
262         vin   += i_uv_pitch - i_uv_visible_pitch;
263         vout  += i_uv_pitch - i_uv_visible_pitch;
264     }
265 }
266
267 static void get_green_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
268                                  int yp, int up, int vp )
269 {
270     uint8_t *y1in = p_inpic->p[yp].p_pixels;
271     uint8_t *y2in;
272     uint8_t *uin  = p_inpic->p[up].p_pixels;
273     uint8_t *vin  = p_inpic->p[vp].p_pixels;
274
275     uint8_t *y1out = p_outpic->p[yp].p_pixels;
276     uint8_t *y2out;
277     uint8_t *uout  = p_outpic->p[up].p_pixels;
278     uint8_t *vout  = p_outpic->p[vp].p_pixels;
279
280     const int i_pitch = p_inpic->p[yp].i_pitch;
281     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
282     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
283
284     const int i_uv_pitch = p_inpic->p[up].i_pitch;
285     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
286
287     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
288     while( y1in < yend )
289     {
290         const uint8_t *y1end = y1in + i_visible_pitch;
291         y2in  = y1in + i_pitch;
292         y2out = y1out + i_pitch;
293         while( y1in < y1end )
294         {
295 /*
296 38470   -13239  -27473
297 -21710  7471    15504
298 -27439  9443    19595
299 */
300             *uout++ = crop( (*y1in * -21710 + (*uin-U) * 7471 + (*vin-V) * 15504)
301                       / 65536 + U );
302             *vout++ = crop( (*y1in * -27439 + (*uin-U) * 9443 + (*vin-V) * 19595)
303                       / 65536 + V );
304             *y1out++ = crop( (*y1in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
305                        / 65536 );
306             *y1out++ = crop( (*y1in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
307                        / 65536 );
308             *y2out++ = crop( (*y2in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
309                        / 65536 );
310             *y2out++ = crop( (*y2in++ * 38470 + (*uin++ - U) * -13239 + (*vin++ -128) * -27473)
311                        / 65536 );
312         }
313         y1in  += 2*i_pitch - i_visible_pitch;
314         y1out += 2*i_pitch - i_visible_pitch;
315         uin   += i_uv_pitch - i_uv_visible_pitch;
316         uout  += i_uv_pitch - i_uv_visible_pitch;
317         vin   += i_uv_pitch - i_uv_visible_pitch;
318         vout  += i_uv_pitch - i_uv_visible_pitch;
319     }
320 }
321
322 static void get_blue_from_yuv420( picture_t *p_inpic, picture_t *p_outpic,
323                                  int yp, int up, int vp )
324 {
325     uint8_t *y1in = p_inpic->p[yp].p_pixels;
326     uint8_t *y2in;
327     uint8_t *uin  = p_inpic->p[up].p_pixels;
328
329     uint8_t *y1out = p_outpic->p[yp].p_pixels;
330     uint8_t *y2out;
331     uint8_t *uout  = p_outpic->p[up].p_pixels;
332     uint8_t *vout  = p_outpic->p[vp].p_pixels;
333
334     const int i_pitch = p_inpic->p[yp].i_pitch;
335     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
336     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
337
338     const int i_uv_pitch = p_inpic->p[up].i_pitch;
339     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
340
341     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
342     while( y1in < yend )
343     {
344         const uint8_t *y1end = y1in + i_visible_pitch;
345         y2in  = y1in + i_pitch;
346         y2out = y1out + i_pitch;
347         while( y1in < y1end )
348         {
349 /*
350 7471    13239   0
351 32768   58065   0
352 -5329   -9443   0
353 */
354             *uout++ = crop( (*y1in* 32768 + (*uin - U) * 58065 )
355                       / 65536 + U );
356             *vout++ = crop( (*y1in * -5329 + (*uin - U) * -9443 )
357                       / 65536 + V );
358             *y1out++ = crop( (*y1in++ * 7471 + (*uin - U) * 13239 )
359                        / 65536 );
360             *y1out++ = crop( (*y1in++ * 7471 + (*uin - U) * 13239 )
361                        / 65536 );
362             *y2out++ = crop( (*y2in++ * 7471 + (*uin - U) * 13239 )
363                        / 65536 );
364             *y2out++ = crop( (*y2in++ * 7471 + (*uin++ - U) * 13239 )
365                        / 65536 );
366         }
367         y1in  += 2*i_pitch - i_visible_pitch;
368         y1out += 2*i_pitch - i_visible_pitch;
369         uin   += i_uv_pitch - i_uv_visible_pitch;
370         uout  += i_uv_pitch - i_uv_visible_pitch;
371         vout  += i_uv_pitch - i_uv_visible_pitch;
372     }
373 }
374
375 static void get_red_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
376                                  int yp, int up, int vp )
377 {
378     uint8_t *y1in = p_inpic->p[yp].p_pixels;
379     uint8_t *vin  = p_inpic->p[vp].p_pixels;
380
381     uint8_t *y1out = p_outpic->p[yp].p_pixels;
382     uint8_t *uout  = p_outpic->p[up].p_pixels;
383     uint8_t *vout  = p_outpic->p[vp].p_pixels;
384
385     const int i_pitch = p_inpic->p[yp].i_pitch;
386     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
387     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
388
389     const int i_uv_pitch = p_inpic->p[up].i_pitch;
390     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
391
392     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
393     while( y1in < yend )
394     {
395         const uint8_t *y1end = y1in + i_visible_pitch;
396         while( y1in < y1end )
397         {
398 /*
399 19595   0   27473
400 -11058  0   -15504
401 32768   0   45941
402 */
403             *uout++ = crop( (*y1in * -11058 + (*vin - V) * -15504)
404                       / 65536 + U );
405             *vout++ = crop( (*y1in * 32768 + (*vin - V) * 45941)
406                       / 65536 + V );
407             *y1out++ = crop( (*y1in++ * 19595 + (*vin - V) * 27473)
408                        / 65536 );
409             *y1out++ = crop( (*y1in++ * 19595 + (*vin++ - V) * 27473)
410                        / 65536 );
411         }
412         y1in  += i_pitch - i_visible_pitch;
413         y1out += i_pitch - i_visible_pitch;
414         uout  += i_uv_pitch - i_uv_visible_pitch;
415         vin   += i_uv_pitch - i_uv_visible_pitch;
416         vout  += i_uv_pitch - i_uv_visible_pitch;
417     }
418 }
419
420 static void get_green_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
421                                    int yp, int up, int vp )
422 {
423     uint8_t *y1in = p_inpic->p[yp].p_pixels;
424     uint8_t *uin  = p_inpic->p[up].p_pixels;
425     uint8_t *vin  = p_inpic->p[vp].p_pixels;
426
427     uint8_t *y1out = p_outpic->p[yp].p_pixels;
428     uint8_t *uout  = p_outpic->p[up].p_pixels;
429     uint8_t *vout  = p_outpic->p[vp].p_pixels;
430
431     const int i_pitch = p_inpic->p[yp].i_pitch;
432     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
433     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
434
435     const int i_uv_pitch = p_inpic->p[up].i_pitch;
436     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
437
438     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
439     while( y1in < yend )
440     {
441         const uint8_t *y1end = y1in + i_visible_pitch;
442         while( y1in < y1end )
443         {
444 /*
445 38470   -13239  -27473
446 -21710  7471    15504
447 -27439  9443    19595
448 */
449             *uout++ = crop( (*y1in * -21710 + (*uin-U) * 7471 + (*vin-V) * 15504)
450                       / 65536 + U );
451             *vout++ = crop( (*y1in * -27439 + (*uin-U) * 9443 + (*vin-V) * 19595)
452                       / 65536 + V );
453             *y1out++ = crop( (*y1in++ * 38470 + (*uin-U) * -13239 + (*vin-V) * -27473)
454                        / 65536 );
455             *y1out++ = crop( (*y1in++ * 38470 + (*uin++-U) * -13239 + (*vin++-V) * -27473)
456                        / 65536 );
457         }
458         y1in  += i_pitch - i_visible_pitch;
459         y1out += i_pitch - i_visible_pitch;
460         uin   += i_uv_pitch - i_uv_visible_pitch;
461         uout  += i_uv_pitch - i_uv_visible_pitch;
462         vin   += i_uv_pitch - i_uv_visible_pitch;
463         vout  += i_uv_pitch - i_uv_visible_pitch;
464     }
465 }
466
467 static void get_blue_from_yuv422( picture_t *p_inpic, picture_t *p_outpic,
468                                  int yp, int up, int vp )
469 {
470     uint8_t *y1in = p_inpic->p[yp].p_pixels;
471     uint8_t *uin  = p_inpic->p[up].p_pixels;
472
473     uint8_t *y1out = p_outpic->p[yp].p_pixels;
474     uint8_t *uout  = p_outpic->p[up].p_pixels;
475     uint8_t *vout  = p_outpic->p[vp].p_pixels;
476
477     const int i_pitch = p_inpic->p[yp].i_pitch;
478     const int i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
479     const int i_visible_lines = p_inpic->p[yp].i_visible_lines;
480
481     const int i_uv_pitch = p_inpic->p[up].i_pitch;
482     const int i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
483
484     const uint8_t *yend = y1in + i_visible_lines * i_pitch;
485     while( y1in < yend )
486     {
487         const uint8_t *y1end = y1in + i_visible_pitch;
488         while( y1in < y1end )
489         {
490 /*
491 7471    13239   0
492 32768   58065   0
493 -5329   -9443   0
494 */
495             *uout++ = crop( (*y1in* 32768 + (*uin - U) * 58065 )
496                       / 65536 + U );
497             *vout++ = crop( (*y1in * -5329 + (*uin - U) * -9443 )
498                       / 65536 + V );
499             *y1out++ = crop( (*y1in++ * 7471 + (*uin - U) * 13239 )
500                        / 65536 );
501             *y1out++ = crop( (*y1in++ * 7471 + (*uin++ - U) * 13239 )
502                        / 65536 );
503         }
504         y1in  += i_pitch - i_visible_pitch;
505         y1out += i_pitch - i_visible_pitch;
506         uin   += i_uv_pitch - i_uv_visible_pitch;
507         uout  += i_uv_pitch - i_uv_visible_pitch;
508         vout  += i_uv_pitch - i_uv_visible_pitch;
509     }
510 }