1 /*****************************************************************************
2 * extract.c : Extract RGB components
3 *****************************************************************************
4 * Copyright (C) 2000-2006 VLC authors and VideoLAN
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 /*****************************************************************************
26 *****************************************************************************/
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 /*****************************************************************************
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 /*****************************************************************************
65 *****************************************************************************/
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
)
81 static const char *const ppsz_filter_options
[] = {
85 enum { RED
=0xFF0000, GREEN
=0x00FF00, BLUE
=0x0000FF };
89 int *projection_matrix
;
93 /*****************************************************************************
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
)
103 case VLC_CODEC_I420_10L
:
104 case VLC_CODEC_I420_10B
:
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
) );
121 /* Allocate structure */
122 p_filter
->p_sys
= malloc( sizeof( filter_sys_t
) );
123 if( p_filter
->p_sys
== NULL
)
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
);
132 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
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
;
149 /*****************************************************************************
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
,
159 vlc_mutex_destroy( &p_sys
->lock
);
160 free( p_sys
->projection_matrix
);
164 /*****************************************************************************
166 *****************************************************************************/
167 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
170 filter_sys_t
*p_sys
= p_filter
->p_sys
;
172 if( !p_pic
) return NULL
;
174 p_outpic
= filter_NewPicture( p_filter
);
177 picture_Release( p_pic
);
181 vlc_mutex_lock( &p_sys
->lock
);
182 switch( p_pic
->format
.i_chroma
)
185 case VLC_CODEC_I420_10L
:
186 case VLC_CODEC_I420_10B
:
191 get_custom_from_yuv( p_pic
, p_outpic
, Y_PLANE
, U_PLANE
, V_PLANE
, p_sys
->projection_matrix
);
195 get_custom_from_packedyuv422( p_pic
, p_outpic
, p_sys
->projection_matrix
);
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
);
205 vlc_mutex_unlock( &p_sys
->lock
);
207 return CopyInfoAndRelease( p_outpic
, p_pic
);
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
++ )
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
);
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
};
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() \
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 ); \
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
)
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
)
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
,
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
,
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
,
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
)
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
;
378 const uint8_t *ylend
= yin
+ i_visible_pitch
;
381 *uout
= vlc_uint8( (*yin
* m
[3] + (*uin
-U8
) * m
[4] + (*vin
-V8
) * m
[5]) / 65536 + U8
);
383 *vout
= vlc_uint8( (*yin
* m
[6] + (*uin
-U8
) * m
[7] + (*vin
-V8
) * m
[8]) / 65536 + V8
);
385 *yout
= vlc_uint8( (*yin
* m
[0] + (*uin
-U8
) * m
[1] + (*vin
-V8
) * m
[2]) / 65536 );
388 *yout
= vlc_uint8( (*yin
* m
[0] + (*uin
-U8
) * m
[1] + (*vin
-V8
) * m
[2]) / 65536 );
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
,
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
);
420 msg_Warn( p_this
, "Unknown callback command." );
422 vlc_mutex_unlock( &p_sys
->lock
);