1 /*****************************************************************************
2 * sepia.c : Sepia video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2010 the VideoLAN team
7 * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37 #include "filter_picture.h"
39 /*****************************************************************************
41 *****************************************************************************/
42 static int Create ( vlc_object_t * );
43 static void Destroy ( vlc_object_t * );
45 static void RVSepia( picture_t *, picture_t *, int );
46 static void PlanarI420Sepia( picture_t *, picture_t *, int);
47 static void PackedYUVSepia( picture_t *, picture_t *, int);
48 static void YuvSepia2( uint8_t *, uint8_t *, uint8_t *, uint8_t *,
49 const uint8_t, const uint8_t, const uint8_t, const uint8_t,
51 static void YuvSepia4( uint8_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *,
52 uint8_t *, const uint8_t, const uint8_t, const uint8_t,
53 const uint8_t, const uint8_t, const uint8_t, int );
54 static void Sepia( int *, int *, int *, int );
55 static picture_t *Filter( filter_t *, picture_t * );
57 static const char *const ppsz_filter_options[] = {
61 /*****************************************************************************
63 *****************************************************************************/
64 #define SEPIA_INTENSITY_TEXT N_("Sepia intensity")
65 #define SEPIA_INTENSITY_LONGTEXT N_("Intensity of sepia effect" )
67 #define CFG_PREFIX "sepia-"
70 set_description( N_("Sepia video filter") )
71 set_shortname( N_("Sepia" ) )
72 set_help( N_("Gives video a warmer tone by applying sepia effect") )
73 set_category( CAT_VIDEO )
74 set_subcategory( SUBCAT_VIDEO_VFILTER )
75 set_capability( "video filter2", 0 )
76 add_integer_with_range( CFG_PREFIX "intensity", 30, 0, 255, NULL,
77 SEPIA_INTENSITY_TEXT, SEPIA_INTENSITY_LONGTEXT,
79 set_callbacks( Create, Destroy )
82 /*****************************************************************************
84 *****************************************************************************/
85 static int FilterCallback( vlc_object_t *, char const *,
86 vlc_value_t, vlc_value_t, void * );
88 typedef void (*SepiaFunction)( picture_t *, picture_t *, int );
92 vlc_fourcc_t i_chroma;
93 SepiaFunction pf_sepia;
95 { VLC_CODEC_I420, PlanarI420Sepia },
96 { VLC_CODEC_RGB24, RVSepia },
97 { VLC_CODEC_RGB32, RVSepia },
98 { VLC_CODEC_UYVY, PackedYUVSepia },
99 { VLC_CODEC_VYUY, PackedYUVSepia },
100 { VLC_CODEC_YUYV, PackedYUVSepia },
101 { VLC_CODEC_YVYU, PackedYUVSepia },
105 /*****************************************************************************
106 * filter_sys_t: adjust filter method descriptor
107 *****************************************************************************/
110 SepiaFunction pf_sepia;
115 /*****************************************************************************
116 * Create: allocates Sepia video thread output method
117 *****************************************************************************
118 * This function allocates and initializes a Sepia vout method.
119 *****************************************************************************/
120 static int Create( vlc_object_t *p_this )
122 filter_t *p_filter = (filter_t *)p_this;
125 /* Allocate structure */
126 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
127 if( p_filter->p_sys == NULL )
130 p_sys->pf_sepia = NULL;
132 for( int i = 0; p_sepia_cfg[i].i_chroma != 0; i++ )
134 if( p_sepia_cfg[i].i_chroma != p_filter->fmt_in.video.i_chroma )
136 p_sys->pf_sepia = p_sepia_cfg[i].pf_sepia;
139 if( p_sys->pf_sepia == NULL )
141 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
142 (char*)&(p_filter->fmt_in.video.i_chroma) );
147 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
149 p_sys->i_intensity= var_CreateGetIntegerCommand( p_filter,
150 CFG_PREFIX "intensity" );
152 vlc_spin_init( &p_sys->lock );
154 var_AddCallback( p_filter, CFG_PREFIX "intensity", FilterCallback, NULL );
156 p_filter->pf_video_filter = Filter;
161 /*****************************************************************************
162 * Destroy: destroy sepia video thread output method
163 *****************************************************************************
164 * Terminate an output method
165 *****************************************************************************/
166 static void Destroy( vlc_object_t *p_this )
168 filter_t *p_filter = (filter_t *)p_this;
170 var_DelCallback( p_filter, CFG_PREFIX "intensity", FilterCallback, NULL );
172 vlc_spin_destroy( &p_filter->p_sys->lock );
173 free( p_filter->p_sys );
176 /*****************************************************************************
177 * Render: displays previously rendered output
178 *****************************************************************************
179 * This function send the currently rendered image to sepia image, waits
180 * until it is displayed and switch the two rendering buffers, preparing next
182 *****************************************************************************/
183 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
188 if( !p_pic ) return NULL;
190 filter_sys_t *p_sys = p_filter->p_sys;
191 vlc_spin_lock( &p_sys->lock );
192 intensity = p_sys->i_intensity;
193 vlc_spin_unlock( &p_sys->lock );
195 p_outpic = filter_NewPicture( p_filter );
198 msg_Warn( p_filter, "can't get output picture" );
199 picture_Release( p_pic );
203 p_sys->pf_sepia( p_pic, p_outpic, intensity );
205 return CopyInfoAndRelease( p_outpic, p_pic );
208 /*****************************************************************************
209 * PlanarI420Sepia: Applies sepia to one frame of the planar I420 video
210 *****************************************************************************
211 * This function applies sepia effect to one frame of the video by iterating
212 * through video lines. We iterate for every two lines and for every two pixels
213 * in line to calculate new sepia values for four y components as well for u
215 *****************************************************************************/
216 static void PlanarI420Sepia( picture_t *p_pic, picture_t *p_outpic,
219 /* iterate for every two visible line in the frame */
220 for( int y = 0; y < p_pic->p[Y_PLANE].i_visible_lines - 1; y += 2)
222 const int i_sy_line1_start = y * p_pic->p[Y_PLANE].i_pitch;
223 const int i_sy_line2_start = ( y + 1 ) * p_pic->p[Y_PLANE].i_pitch;
224 const int i_su_line_start = (y/2) * p_pic->p[U_PLANE].i_pitch;
225 const int i_sv_line_start = (y/2) * p_pic->p[V_PLANE].i_pitch;
227 const int i_dy_line1_start = y * p_outpic->p[Y_PLANE].i_pitch;
228 const int i_dy_line2_start = ( y + 1 ) * p_outpic->p[Y_PLANE].i_pitch;
229 const int i_du_line_start = (y/2) * p_outpic->p[U_PLANE].i_pitch;
230 const int i_dv_line_start = (y/2) * p_outpic->p[V_PLANE].i_pitch;
231 /* iterate for every two visible line in the frame */
232 for( int x = 0; x < p_pic->p[Y_PLANE].i_visible_pitch - 1; x += 2)
234 uint8_t sy1, sy2, sy3, sy4, su, sv;
235 uint8_t dy1, dy2, dy3, dy4, du, dv;
236 const int i_sy_line1_offset = i_sy_line1_start + x;
237 const int i_sy_line2_offset = i_sy_line2_start + x;
238 const int i_dy_line1_offset = i_dy_line1_start + x;
239 const int i_dy_line2_offset = i_dy_line2_start + x;
240 /* get four y components and u and v component */
241 sy1 = p_pic->p[Y_PLANE].p_pixels[i_sy_line1_offset];
242 sy2 = p_pic->p[Y_PLANE].p_pixels[i_sy_line1_offset + 1];
243 sy3 = p_pic->p[Y_PLANE].p_pixels[i_sy_line2_offset];
244 sy4 = p_pic->p[Y_PLANE].p_pixels[i_sy_line2_offset + 1];
245 su = p_pic->p[U_PLANE].p_pixels[i_su_line_start + (x/2)];
246 sv = p_pic->p[V_PLANE].p_pixels[i_sv_line_start + (x/2)];
247 /* calculate sepia values */
248 YuvSepia4( &dy1, &dy2, &dy3, &dy4, &du, &dv,
249 sy1, sy2, sy3, sy4, su, sv, i_intensity );
250 /* put new sepia values for all four y components and u and v */
251 p_outpic->p[Y_PLANE].p_pixels[i_dy_line1_offset] = dy1;
252 p_outpic->p[Y_PLANE].p_pixels[i_dy_line1_offset + 1] = dy2;
253 p_outpic->p[Y_PLANE].p_pixels[i_dy_line2_offset] = dy3;
254 p_outpic->p[Y_PLANE].p_pixels[i_dy_line2_offset + 1] = dy4;
255 p_outpic->p[U_PLANE].p_pixels[i_du_line_start + (x/2)] = du;
256 p_outpic->p[V_PLANE].p_pixels[i_dv_line_start + (x/2)] = dv;
261 /*****************************************************************************
262 * PackedYUVSepia: Applies sepia to one frame of the packed YUV video
263 *****************************************************************************
264 * This function applies sepia effext to one frame of the video by iterating
265 * through video lines. In every pass, we calculate new values for pixels
266 * (UYVY, VYUY, YUYV and YVYU formats are supported)
267 *****************************************************************************/
268 static void PackedYUVSepia( picture_t *p_pic, picture_t *p_outpic,
271 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
272 int i_yindex = 1, i_uindex = 2, i_vindex = 0;
274 GetPackedYuvOffsets( p_outpic->format.i_chroma,
275 &i_yindex, &i_uindex, &i_vindex );
277 p_in = p_pic->p[0].p_pixels;
278 p_in_end = p_in + p_pic->p[0].i_visible_lines
279 * p_pic->p[0].i_pitch;
280 p_out = p_outpic->p[0].p_pixels;
282 while( p_in < p_in_end )
285 p_line_end = p_in + p_pic->p[0].i_visible_pitch;
286 while( p_in < p_line_end )
288 /* calculate new, sepia values */
289 YuvSepia2( &p_out[i_yindex], &p_out[i_yindex + 2], &p_out[i_uindex],
290 &p_out[i_vindex], p_in[i_yindex], p_in[i_yindex + 2],
291 p_in[i_uindex], p_in[i_vindex], i_intensity );
295 p_in += p_pic->p[0].i_pitch - p_pic->p[0].i_visible_pitch;
296 p_out += p_outpic->p[0].i_pitch
297 - p_outpic->p[0].i_visible_pitch;
301 /*****************************************************************************
302 * RVSepia: Applies sepia to one frame of the RV24/RV32 video
303 *****************************************************************************
304 * This function applies sepia effect to one frame of the video by iterating
305 * through video lines and calculating new values for every byte in chunks of
306 * 3 (RV24) or 4 (RV32) bytes.
307 *****************************************************************************/
308 static void RVSepia( picture_t *p_pic, picture_t *p_outpic, int i_intensity )
310 uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
312 bool b_isRV32 = p_pic->format.i_chroma == VLC_CODEC_RGB32;
313 int i_rindex = 0, i_gindex = 1, i_bindex = 2;
315 GetPackedRgbIndexes( &p_outpic->format, &i_rindex, &i_gindex, &i_bindex );
317 p_in = p_pic->p[0].p_pixels;
318 p_in_end = p_in + p_pic->p[0].i_visible_lines
319 * p_pic->p[0].i_pitch;
320 p_out = p_outpic->p[0].p_pixels;
322 while( p_in < p_in_end )
325 p_line_end = p_in + p_pic->p[0].i_visible_pitch;
326 while( p_in < p_line_end )
328 /* extract r,g,b values */
329 i_r = p_in[i_rindex];
330 i_g = p_in[i_gindex];
331 i_b = p_in[i_bindex];
334 Sepia( &i_r, &i_g, &i_b, i_intensity );
335 /* put new r,g,b values */
336 p_out[i_rindex] = i_r;
337 p_out[i_gindex] = i_g;
338 p_out[i_bindex] = i_b;
340 /* for rv32 we take 4 chunks at the time */
343 /* alpha channel stays the same */
347 p_in += p_pic->p[0].i_pitch - p_pic->p[0].i_visible_pitch;
348 p_out += p_outpic->p[0].i_pitch
349 - p_outpic->p[0].i_visible_pitch;
353 /*****************************************************************************
354 * YuvSepia2: Calculates sepia to YUV values for two given Y values
355 *****************************************************************************
356 * This function calculates sepia values of YUV color space for a given sepia
357 * intensity. It converts YUV color values to theirs RGB equivalents,
358 * calculates sepia values and then converts RGB values to YUV values again.
359 *****************************************************************************/
360 static void YuvSepia2( uint8_t* sepia_y1, uint8_t* sepia_y2, uint8_t* sepia_u,
361 uint8_t* sepia_v, const uint8_t y1, const uint8_t y2,
362 const uint8_t u, const uint8_t v, int i_intensity )
364 int r1, g1, b1; /* for y1 new value */
365 int r2, b2, g2; /* for y2 new value */
366 int r3, g3, b3; /* for new values of u and v */
367 /* fist convert YUV -> RGB */
368 yuv_to_rgb( &r1, &g1, &b1, y1, u, v );
369 yuv_to_rgb( &r2, &g2, &b2, y2, u, v );
370 yuv_to_rgb( &r3, &g3, &b3, ( y1 + y2 ) / 2, u, v );
371 /* calculates new values for r, g and b components */
372 Sepia( &r1, &g1, &b1, i_intensity );
373 Sepia( &r2, &g2, &b2, i_intensity );
374 Sepia( &r3, &g3, &b3, i_intensity );
375 /* convert from calculated RGB -> YUV */
376 *sepia_y1 = ( ( 66 * r1 + 129 * g1 + 25 * b1 + 128 ) >> 8 ) + 16;
377 *sepia_y2 = ( ( 66 * r2 + 129 * g2 + 25 * b2 + 128 ) >> 8 ) + 16;
378 *sepia_u = ( ( -38 * r3 - 74 * g3 + 112 * b3 + 128 ) >> 8 ) + 128;
379 *sepia_v = ( ( 112 * r3 - 94 * g3 - 18 * b3 + 128 ) >> 8 ) + 128;
382 /*****************************************************************************
383 * YuvSepia4: Calculates sepia to YUV values for given four Y values
384 *****************************************************************************
385 * This function calculates sepia values of YUV color space for a given sepia
386 * intensity. It converts YUV color values to theirs RGB equivalents,
387 * calculates sepia values and then converts RGB values to YUV values again.
388 *****************************************************************************/
389 static void YuvSepia4( uint8_t* sepia_y1, uint8_t* sepia_y2, uint8_t* sepia_y3,
390 uint8_t* sepia_y4, uint8_t* sepia_u, uint8_t* sepia_v,
391 const uint8_t y1, const uint8_t y2, const uint8_t y3,
392 const uint8_t y4, const uint8_t u, uint8_t v,
395 int r1, g1, b1; /* for y1 new value */
396 int r2, b2, g2; /* for y2 new value */
397 int r3, b3, g3; /* for y3 new value */
398 int r4, b4, g4; /* for y4 new value */
399 int r5, g5, b5; /* for new values of u and v */
400 /* fist convert YUV -> RGB */
401 yuv_to_rgb( &r1, &g1, &b1, y1, u, v );
402 yuv_to_rgb( &r2, &g2, &b2, y2, u, v );
403 yuv_to_rgb( &r3, &g3, &b3, y3, u, v );
404 yuv_to_rgb( &r4, &g4, &b4, y4, u, v );
405 yuv_to_rgb( &r5, &g5, &b5, ( y1 + y2 + y3 + y4) / 4, u, v );
406 /* calculates new values for r, g and b components */
407 Sepia( &r1, &g1, &b1, i_intensity );
408 Sepia( &r2, &g2, &b2, i_intensity );
409 Sepia( &r3, &g3, &b3, i_intensity );
410 Sepia( &r4, &g4, &b4, i_intensity );
411 Sepia( &r5, &g5, &b5, i_intensity );
412 /* convert from calculated RGB -> YUV */
413 *sepia_y1 = ( ( 66 * r1 + 129 * g1 + 25 * b1 + 128 ) >> 8 ) + 16;
414 *sepia_y2 = ( ( 66 * r2 + 129 * g2 + 25 * b2 + 128 ) >> 8 ) + 16;
415 *sepia_y3 = ( ( 66 * r3 + 129 * g3 + 25 * b3 + 128 ) >> 8 ) + 16;
416 *sepia_y4 = ( ( 66 * r4 + 129 * g4 + 25 * b4 + 128 ) >> 8 ) + 16;
417 *sepia_u = ( ( -38 * r5 - 74 * g5 + 112 * b5 + 128 ) >> 8 ) + 128;
418 *sepia_v = ( ( 112 * r5 - 94 * g5 - 18 * b5 + 128 ) >> 8 ) + 128;
421 /*****************************************************************************
422 * Sepia: Calculates sepia of RGB values
423 *****************************************************************************
424 * This function calculates sepia values of RGB color space for a given sepia
425 * intensity. Sepia algorithm is taken from here:
426 * http://groups.google.com/group/comp.lang.java.programmer/browse_thread/
427 * thread/9d20a72c40b119d0/18f12770ec6d9dd6
428 *****************************************************************************/
429 static void Sepia( int *p_r, int *p_g, int *p_b, int i_intensity )
431 int i_sepia_depth = 20;
433 i_round = ( *p_r + *p_g + *p_b ) / 3;
434 *p_r = vlc_uint8( i_round + ( i_sepia_depth * 2 ) );
435 *p_g = vlc_uint8( i_round + i_sepia_depth );
436 *p_b = vlc_uint8( i_round - i_intensity );
439 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
440 vlc_value_t oldval, vlc_value_t newval,
443 VLC_UNUSED(psz_var); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
444 filter_t *p_filter = (filter_t*)p_this;
445 filter_sys_t *p_sys = p_filter->p_sys;
447 vlc_spin_lock( &p_sys->lock );
448 p_sys->i_intensity = newval.i_int;
449 vlc_spin_unlock( &p_sys->lock );