libVLC: comment the ranges for viewpoint
[vlc.git] / modules / video_filter / extract.c
blob8e349f1372caf9f997db9e002be60eae9c56ed85
1 /*****************************************************************************
2 * extract.c : Extract RGB components
3 *****************************************************************************
4 * Copyright (C) 2000-2006 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Antoine Cellerier <dionoea .t videolan d@t org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <math.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37 #include <vlc_picture.h>
38 #include "filter_picture.h"
40 /*****************************************************************************
41 * Local prototypes
42 *****************************************************************************/
43 static int Create ( vlc_object_t * );
44 static void Destroy ( vlc_object_t * );
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 * );
50 static void make_projection_matrix( filter_t *, int color, int *matrix );
51 static void get_custom_from_yuv( picture_t *, picture_t *, int, int, int, int const * );
52 static void get_custom_from_packedyuv422( picture_t *, picture_t *, int * );
55 #define COMPONENT_TEXT N_("RGB component to extract")
56 #define COMPONENT_LONGTEXT N_("RGB component to extract. 0 for Red, 1 for Green and 2 for Blue.")
57 #define FILTER_PREFIX "extract-"
59 static const int pi_component_values[] = { 0xFF0000, 0x00FF00, 0x0000FF };
60 static const char *const ppsz_component_descriptions[] = {
61 "Red", "Green", "Blue" };
63 /*****************************************************************************
64 * Module descriptor
65 *****************************************************************************/
66 vlc_module_begin ()
67 set_description( N_("Extract RGB component video filter") )
68 set_shortname( N_("Extract" ))
69 set_category( CAT_VIDEO )
70 set_subcategory( SUBCAT_VIDEO_VFILTER )
71 set_capability( "video filter", 0 )
72 add_shortcut( "extract" )
74 add_integer_with_range( FILTER_PREFIX "component", 0xFF0000, 1, 0xFFFFFF,
75 COMPONENT_TEXT, COMPONENT_LONGTEXT, false )
76 change_integer_list( pi_component_values, ppsz_component_descriptions )
78 set_callbacks( Create, Destroy )
79 vlc_module_end ()
81 static const char *const ppsz_filter_options[] = {
82 "component", NULL
85 enum { RED=0xFF0000, GREEN=0x00FF00, BLUE=0x0000FF };
86 struct filter_sys_t
88 vlc_mutex_t lock;
89 int *projection_matrix;
90 uint32_t i_color;
93 /*****************************************************************************
94 * Create
95 *****************************************************************************/
96 static int Create( vlc_object_t *p_this )
98 filter_t *p_filter = (filter_t *)p_this;
100 switch( p_filter->fmt_in.video.i_chroma )
102 case VLC_CODEC_I420:
103 case VLC_CODEC_I420_10L:
104 case VLC_CODEC_I420_10B:
105 case VLC_CODEC_J420:
106 case VLC_CODEC_YV12:
108 case VLC_CODEC_I422:
109 case VLC_CODEC_J422:
111 CASE_PACKED_YUV_422
112 break;
114 default:
115 /* We only want planar YUV 4:2:0 or 4:2:2 */
116 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
117 (char*)&(p_filter->fmt_in.video.i_chroma) );
118 return VLC_EGENERIC;
121 /* Allocate structure */
122 p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
123 if( p_filter->p_sys == NULL )
124 return VLC_ENOMEM;
125 p_filter->p_sys->projection_matrix = malloc( 9 * sizeof( int ) );
126 if( !p_filter->p_sys->projection_matrix )
128 free( p_filter->p_sys );
129 return VLC_ENOMEM;
132 config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
133 p_filter->p_cfg );
135 p_filter->p_sys->i_color = var_CreateGetIntegerCommand( p_filter,
136 FILTER_PREFIX "component" );
137 /* Matrix won't be used for RED, GREEN or BLUE in planar formats */
138 make_projection_matrix( p_filter, p_filter->p_sys->i_color,
139 p_filter->p_sys->projection_matrix );
140 vlc_mutex_init( &p_filter->p_sys->lock );
141 var_AddCallback( p_filter, FILTER_PREFIX "component",
142 ExtractCallback, p_filter->p_sys );
144 p_filter->pf_video_filter = Filter;
146 return VLC_SUCCESS;
149 /*****************************************************************************
150 * Destroy
151 *****************************************************************************/
152 static void Destroy( vlc_object_t *p_this )
154 filter_t *p_filter = (filter_t *)p_this;
155 filter_sys_t *p_sys = p_filter->p_sys;
157 var_DelCallback( p_filter, FILTER_PREFIX "component", ExtractCallback,
158 p_sys );
159 vlc_mutex_destroy( &p_sys->lock );
160 free( p_sys->projection_matrix );
161 free( p_sys );
164 /*****************************************************************************
165 * Render
166 *****************************************************************************/
167 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
169 picture_t *p_outpic;
170 filter_sys_t *p_sys = p_filter->p_sys;
172 if( !p_pic ) return NULL;
174 p_outpic = filter_NewPicture( p_filter );
175 if( !p_outpic )
177 picture_Release( p_pic );
178 return NULL;
181 vlc_mutex_lock( &p_sys->lock );
182 switch( p_pic->format.i_chroma )
184 case VLC_CODEC_I420:
185 case VLC_CODEC_I420_10L:
186 case VLC_CODEC_I420_10B:
187 case VLC_CODEC_J420:
188 case VLC_CODEC_YV12:
189 case VLC_CODEC_I422:
190 case VLC_CODEC_J422:
191 get_custom_from_yuv( p_pic, p_outpic, Y_PLANE, U_PLANE, V_PLANE, p_sys->projection_matrix );
192 break;
194 CASE_PACKED_YUV_422
195 get_custom_from_packedyuv422( p_pic, p_outpic, p_sys->projection_matrix );
196 break;
198 default:
199 vlc_mutex_unlock( &p_sys->lock );
200 msg_Warn( p_filter, "Unsupported input chroma (%4.4s)",
201 (char*)&(p_pic->format.i_chroma) );
202 picture_Release( p_pic );
203 return NULL;
205 vlc_mutex_unlock( &p_sys->lock );
207 return CopyInfoAndRelease( p_outpic, p_pic );
210 #define U8 128
211 #define V8 128
213 #define U10 512
214 #define V10 512
216 static void mmult( double *res, double *a, double *b )
218 for( int i = 0; i < 3; i++ )
220 for( int j = 0; j < 3; j++ )
222 res[ i*3 + j ] = 0.;
223 for( int k = 0; k < 3; k++ )
225 res[ i*3 + j ] += a[ i*3 + k ] * b[ k*3 + j ];
230 static void make_projection_matrix( filter_t *p_filter, int color, int *matrix )
232 double left_matrix[9] =
233 { 76.24500, 149.68500, 29.07000,
234 -43.02765, -84.47235, 127.50000,
235 127.50000, -106.76534, -20.73466 };
236 double right_matrix[9] =
237 { 257.00392, 0.00000, 360.31950,
238 257.00392, -88.44438, -183.53583,
239 257.00392, 455.41095, 0.00000 };
240 double red = ((double)(( 0xFF0000 & color )>>16))/255.;
241 double green = ((double)(( 0x00FF00 & color )>>8))/255.;
242 double blue = ((double)( 0x0000FF & color ))/255.;
243 double norm = sqrt( red*red + green*green + blue*blue );
244 if( norm > 0 )
246 red /= norm;
247 green /= norm;
248 blue /= norm;
250 /* XXX: We might still need to norm the rgb_matrix */
251 double rgb_matrix[9] =
252 { red*red, red*green, red*blue,
253 red*green, green*green, green*blue,
254 red*blue, green*blue, blue*blue };
255 double result1[9];
256 double result[9];
257 msg_Dbg( p_filter, "red: %f", red );
258 msg_Dbg( p_filter, "green: %f", green );
259 msg_Dbg( p_filter, "blue: %f", blue );
260 mmult( result1, rgb_matrix, right_matrix );
261 mmult( result, left_matrix, result1 );
262 for( int i = 0; i < 9; i++ )
264 matrix[i] = (int)result[i];
266 msg_Dbg( p_filter, "Projection matrix:" );
267 msg_Dbg( p_filter, "%6d %6d %6d", matrix[0], matrix[1], matrix[2] );
268 msg_Dbg( p_filter, "%6d %6d %6d", matrix[3], matrix[4], matrix[5] );
269 msg_Dbg( p_filter, "%6d %6d %6d", matrix[6], matrix[7], matrix[8] );
272 #define IS_YUV_10BITS(fmt) (fmt == VLC_CODEC_I420_10L || fmt == VLC_CODEC_I420_10B)
274 #define GET_CUSTOM_PIX() \
275 do \
277 val = (*y_in[0] * m[3] + (**u_in - u) * m[4] + (**v_in - v) * m[5]) / 65536 + u; \
278 *(*u_out)++ = VLC_CLIP( val, 0, maxval ); \
279 val = (*y_in[0] * m[6] + (**u_in - u) * m[7] + (**v_in - v) * m[8]) / 65536 + v; \
280 *(*v_out)++ = VLC_CLIP( val, 0, maxval ); \
281 val = (*y_in[0]++ * m[0] + (**u_in - u) * m[1] + (**v_in - v) * m[2]) / 65536; \
282 *y_out[0]++ = VLC_CLIP( val, 0, maxval ); \
283 val = (*y_in[0]++ * m[0] + (**u_in - u) * m[1] + (**v_in - v) * m[2]) / 65536; \
284 *y_out[0]++ = VLC_CLIP( val, 0, maxval ); \
285 val = (*y_in[1]++ * m[0] + (**u_in - u) * m[1] + (**v_in - v) * m[2]) / 65536; \
286 *y_out[1]++ = VLC_CLIP( val, 0, maxval ); \
287 val = (*y_in[1]++ * m[0] + (*(*u_in)++ - u) * m[1] + (*(*v_in)++ - v) * m[2]) / 65536; \
288 *y_out[1]++ = VLC_CLIP( val, 0, maxval ); \
289 } while (0);
291 static inline void
292 get_custom_pix_8b( uint8_t *y_in[2], uint8_t *y_out[2],
293 uint8_t **u_in, uint8_t **u_out,
294 uint8_t **v_in, uint8_t **v_out,
295 uint16_t const u, uint16_t const v,
296 int const *m, int maxval )
298 uint8_t val;
299 GET_CUSTOM_PIX();
302 static inline void
303 get_custom_pix_10b( uint16_t *y_in[2], uint16_t *y_out[2],
304 uint16_t **u_in, uint16_t **u_out,
305 uint16_t **v_in, uint16_t **v_out,
306 uint16_t const u, uint16_t const v,
307 int const *m, int maxval )
309 uint16_t val;
310 GET_CUSTOM_PIX();
313 static void
314 get_custom_from_yuv( picture_t *p_inpic, picture_t *p_outpic,
315 int const yp, int const up, int const vp, int const *m )
317 int const i_in_pitch = p_inpic->p[yp].i_pitch;
318 int const i_out_pitch = p_outpic->p[yp].i_pitch;
319 int const i_visible_pitch = p_inpic->p[yp].i_visible_pitch;
320 int const i_visible_lines = p_inpic->p[yp].i_visible_lines;
321 int const i_uv_visible_pitch = p_inpic->p[up].i_visible_pitch;
322 uint8_t *y_in[2] = { p_inpic->p[yp].p_pixels };
323 uint8_t *u_in = p_inpic->p[up].p_pixels;
324 uint8_t *v_in = p_inpic->p[vp].p_pixels;
325 uint8_t *y_out[2] = { p_outpic->p[yp].p_pixels };
326 uint8_t *u_out = p_outpic->p[up].p_pixels;
327 uint8_t *v_out = p_outpic->p[vp].p_pixels;
328 uint8_t *const y_end = y_in[0] + i_visible_lines * i_in_pitch;
330 while (y_in[0] < y_end)
332 y_in[1] = y_in[0] + i_in_pitch;
333 y_out[1] = y_out[0] + i_out_pitch;
334 for (uint8_t *const y_row_end = y_in[0] + i_visible_pitch; y_in[0] < y_row_end; )
336 !IS_YUV_10BITS(p_inpic->format.i_chroma)
337 ? get_custom_pix_8b(y_in, y_out, &u_in, &u_out, &v_in, &v_out, U8,
338 V8, m, 255)
339 : get_custom_pix_10b((uint16_t **)y_in, (uint16_t **)y_out,
340 (uint16_t **)&u_in, (uint16_t **)&u_out,
341 (uint16_t **)&v_in, (uint16_t **)&v_out, U10,
342 V10, m, 1023);
344 y_in[0] += 2 * i_in_pitch - i_visible_pitch;
345 y_out[0] += 2 * i_out_pitch - i_visible_pitch;
346 u_in += p_inpic->p[up].i_pitch - i_uv_visible_pitch;
347 u_out += p_outpic->p[up].i_pitch - i_uv_visible_pitch;
348 v_in += p_inpic->p[vp].i_pitch - i_uv_visible_pitch;
349 v_out += p_outpic->p[vp].i_pitch - i_uv_visible_pitch;
353 static void get_custom_from_packedyuv422( picture_t *p_inpic,
354 picture_t *p_outpic,
355 int *m )
357 int i_y_offset, i_u_offset, i_v_offset;
358 if( GetPackedYuvOffsets( p_inpic->format.i_chroma, &i_y_offset,
359 &i_u_offset, &i_v_offset ) != VLC_SUCCESS )
360 return;
362 uint8_t *yin = p_inpic->p->p_pixels + i_y_offset;
363 uint8_t *uin = p_inpic->p->p_pixels + i_u_offset;
364 uint8_t *vin = p_inpic->p->p_pixels + i_v_offset;
366 uint8_t *yout = p_outpic->p->p_pixels + i_y_offset;
367 uint8_t *uout = p_outpic->p->p_pixels + i_u_offset;
368 uint8_t *vout = p_outpic->p->p_pixels + i_v_offset;
370 const int i_in_pitch = p_inpic->p->i_pitch;
371 const int i_out_pitch = p_outpic->p->i_pitch;
372 const int i_visible_pitch = p_inpic->p->i_visible_pitch;
373 const int i_visible_lines = p_inpic->p->i_visible_lines;
375 const uint8_t *yend = yin + i_visible_lines * i_in_pitch;
376 while( yin < yend )
378 const uint8_t *ylend = yin + i_visible_pitch;
379 while( yin < ylend )
381 *uout = vlc_uint8( (*yin * m[3] + (*uin-U8) * m[4] + (*vin-V8) * m[5]) / 65536 + U8 );
382 uout += 4;
383 *vout = vlc_uint8( (*yin * m[6] + (*uin-U8) * m[7] + (*vin-V8) * m[8]) / 65536 + V8 );
384 vout += 4;
385 *yout = vlc_uint8( (*yin * m[0] + (*uin-U8) * m[1] + (*vin-V8) * m[2]) / 65536 );
386 yin += 2;
387 yout += 2;
388 *yout = vlc_uint8( (*yin * m[0] + (*uin-U8) * m[1] + (*vin-V8) * m[2]) / 65536 );
389 yin += 2;
390 yout += 2;
391 uin += 4;
392 vin += 4;
394 yin += i_in_pitch - i_visible_pitch;
395 yout += i_out_pitch - i_visible_pitch;
396 uin += i_in_pitch - i_visible_pitch;
397 uout += i_out_pitch - i_visible_pitch;
398 vin += i_in_pitch - i_visible_pitch;
399 vout += i_out_pitch - i_visible_pitch;
403 static int ExtractCallback( vlc_object_t *p_this, char const *psz_var,
404 vlc_value_t oldval, vlc_value_t newval,
405 void *p_data )
407 VLC_UNUSED(oldval);
408 filter_sys_t *p_sys = (filter_sys_t *)p_data;
410 vlc_mutex_lock( &p_sys->lock );
411 if( !strcmp( psz_var, FILTER_PREFIX "component" ) )
413 p_sys->i_color = newval.i_int;
414 /* Matrix won't be used for RED, GREEN or BLUE in planar formats */
415 make_projection_matrix( (filter_t *)p_this, p_sys->i_color,
416 p_sys->projection_matrix );
418 else
420 msg_Warn( p_this, "Unknown callback command." );
422 vlc_mutex_unlock( &p_sys->lock );
423 return VLC_SUCCESS;