]> git.sesse.net Git - vlc/blob - modules/video_filter/sepia.c
video filter refactor (trying to reuse functions)
[vlc] / modules / video_filter / sepia.c
1 /*****************************************************************************
2  * sepia.c : Sepia video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2010 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
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
35 #include <assert.h>
36 #include <vlc_filter.h>
37 #include "filter_picture.h"
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 static int  Create      ( vlc_object_t * );
43 static void Destroy     ( vlc_object_t * );
44
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,
50                       int );
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 * );
56
57 static const char *const ppsz_filter_options[] = {
58     "intensity", NULL
59 };
60
61 /*****************************************************************************
62  * Module descriptor
63  *****************************************************************************/
64 #define SEPIA_INTENSITY_TEXT N_("Sepia intensity")
65 #define SEPIA_INTENSITY_LONGTEXT N_("Intensity of sepia effect" )
66
67 #define CFG_PREFIX "sepia-"
68
69 vlc_module_begin ()
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,
78                            false )
79     set_callbacks( Create, Destroy )
80 vlc_module_end ()
81
82 /*****************************************************************************
83  * callback prototypes
84  *****************************************************************************/
85 static int FilterCallback( vlc_object_t *, char const *,
86                            vlc_value_t, vlc_value_t, void * );
87
88 typedef void (*SepiaFunction)( picture_t *, picture_t *, int );
89
90 static const struct
91 {
92     vlc_fourcc_t i_chroma;
93     SepiaFunction pf_sepia;
94 } p_sepia_cfg[] = {
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 },
102     { 0, NULL }
103 };
104
105 /*****************************************************************************
106  * filter_sys_t: adjust filter method descriptor
107  *****************************************************************************/
108 struct filter_sys_t
109 {
110     SepiaFunction pf_sepia;
111     int i_intensity;
112     vlc_spinlock_t lock;
113 };
114
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 )
121 {
122     filter_t *p_filter = (filter_t *)p_this;
123     filter_sys_t *p_sys;
124
125     /* Allocate structure */
126     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
127     if( p_filter->p_sys == NULL )
128         return VLC_ENOMEM;
129
130     p_sys->pf_sepia = NULL;
131
132     for( int i = 0; p_sepia_cfg[i].i_chroma != 0; i++ )
133     {
134         if( p_sepia_cfg[i].i_chroma != p_filter->fmt_in.video.i_chroma )
135             continue;
136         p_sys->pf_sepia = p_sepia_cfg[i].pf_sepia;
137     }
138
139     if( p_sys->pf_sepia == NULL )
140     {
141         msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
142                 (char*)&(p_filter->fmt_in.video.i_chroma) );
143         free( p_sys );
144         return VLC_EGENERIC;
145     }
146
147     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
148                        p_filter->p_cfg );
149     p_sys->i_intensity= var_CreateGetIntegerCommand( p_filter,
150                        CFG_PREFIX "intensity" );
151
152     vlc_spin_init( &p_sys->lock );
153
154     var_AddCallback( p_filter, CFG_PREFIX "intensity", FilterCallback, NULL );
155
156     p_filter->pf_video_filter = Filter;
157
158     return VLC_SUCCESS;
159 }
160
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 )
167 {
168     filter_t *p_filter = (filter_t *)p_this;
169
170     var_DelCallback( p_filter, CFG_PREFIX "intensity", FilterCallback, NULL );
171
172     vlc_spin_destroy( &p_filter->p_sys->lock );
173     free( p_filter->p_sys );
174 }
175
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
181  * frame.
182  *****************************************************************************/
183 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
184 {
185     picture_t *p_outpic;
186     int intensity;
187
188     if( !p_pic ) return NULL;
189
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 );
194
195     p_outpic = filter_NewPicture( p_filter );
196     if( !p_outpic )
197     {
198         msg_Warn( p_filter, "can't get output picture" );
199         picture_Release( p_pic );
200         return NULL;
201     }
202
203     p_sys->pf_sepia( p_pic, p_outpic, intensity );
204
205     return CopyInfoAndRelease( p_outpic, p_pic );
206 }
207
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
214  * and v components.
215  *****************************************************************************/
216 static void PlanarI420Sepia( picture_t *p_pic, picture_t *p_outpic,
217                                int i_intensity )
218 {
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)
221     {
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;
226
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)
233         {
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;
257             }
258     }
259 }
260
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,
269                            int i_intensity )
270 {
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;
273
274     GetPackedYuvOffsets( p_outpic->format.i_chroma,
275                         &i_yindex, &i_uindex, &i_vindex );
276
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;
281
282     while( p_in < p_in_end )
283     {
284         p_line_start = p_in;
285         p_line_end = p_in + p_pic->p[0].i_visible_pitch;
286         while( p_in < p_line_end )
287         {
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 );
292             p_in += 4;
293             p_out += 4;
294         }
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;
298     }
299 }
300
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 )
309 {
310     uint8_t *p_in, *p_in_end, *p_line_start, *p_line_end, *p_out;
311     int i_r, i_g, i_b;
312     bool b_isRV32 = p_pic->format.i_chroma == VLC_CODEC_RGB32;
313     int i_rindex = 0, i_gindex = 1, i_bindex = 2;
314
315     GetPackedRgbIndexes( &p_outpic->format, &i_rindex, &i_gindex, &i_bindex );
316
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;
321
322     while( p_in < p_in_end )
323     {
324         p_line_start = p_in;
325         p_line_end = p_in + p_pic->p[0].i_visible_pitch;
326         while( p_in < p_line_end )
327         {
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];
332             p_in += 3;
333             /* do sepia */
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;
339             p_out += 3;
340             /* for rv32 we take 4 chunks at the time */
341             if ( b_isRV32 )
342             {
343                 /* alpha channel stays the same */
344                 *p_out++ = *p_in++;
345             }
346         }
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;
350     }
351 }
352
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 )
363 {
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;
380 }
381
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,
393                       int i_intensity )
394 {
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;
419 }
420
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 )
430 {
431     int i_sepia_depth = 20;
432     int16_t i_round;
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 );
437 }
438
439 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
440                             vlc_value_t oldval, vlc_value_t newval,
441                             void *p_data )
442 {
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;
446
447     vlc_spin_lock( &p_sys->lock );
448     p_sys->i_intensity = newval.i_int;
449     vlc_spin_unlock( &p_sys->lock );
450
451     return VLC_SUCCESS;
452 }