demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / video_filter / posterize.c
blob2eab2d70193355b12361ca122c86137c29ec7740
1 /*****************************************************************************
2 * posterize.c : Posterize video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2010 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Branko Kokanovic <branko.kokanovic@gmail.com>
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 <assert.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_atomic.h>
37 #include <vlc_filter.h>
38 #include <vlc_picture.h>
39 #include "filter_picture.h"
41 /*****************************************************************************
42 * Local prototypes
43 *****************************************************************************/
44 static int Create ( vlc_object_t * );
45 static void Destroy ( vlc_object_t * );
47 static picture_t *Filter( filter_t *, picture_t * );
48 static void PlanarYUVPosterize( picture_t *, picture_t *, int);
49 static void PackedYUVPosterize( picture_t *, picture_t *, int);
50 static void RVPosterize( picture_t *, picture_t *, bool, int );
51 static void YuvPosterization( uint8_t *, uint8_t *, uint8_t *, uint8_t *,
52 uint8_t, uint8_t, uint8_t, uint8_t, int );
54 static const char *const ppsz_filter_options[] = {
55 "level", NULL
58 /*****************************************************************************
59 * Module descriptor
60 *****************************************************************************/
61 #define POSTERIZE_LEVEL_TEXT N_("Posterize level")
62 #define POSTERIZE_LEVEL_LONGTEXT N_("Posterize level "\
63 "(number of colors is cube of this value)" )
65 #define CFG_PREFIX "posterize-"
67 vlc_module_begin ()
68 set_description( N_("Posterize video filter") )
69 set_shortname( N_("Posterize" ) )
70 set_help( N_("Posterize video by lowering the number of colors") )
71 set_category( CAT_VIDEO )
72 set_subcategory( SUBCAT_VIDEO_VFILTER )
73 set_capability( "video filter", 0 )
74 add_integer_with_range( CFG_PREFIX "level", 6, 2, 256,
75 POSTERIZE_LEVEL_TEXT, POSTERIZE_LEVEL_LONGTEXT,
76 false )
77 set_callbacks( Create, Destroy )
78 vlc_module_end ()
80 /*****************************************************************************
81 * callback prototypes
82 *****************************************************************************/
83 static int FilterCallback( vlc_object_t *, char const *,
84 vlc_value_t, vlc_value_t, void * );
86 /*****************************************************************************
87 * filter_sys_t: adjust filter method descriptor
88 *****************************************************************************/
89 struct filter_sys_t
91 atomic_int i_level;
94 /*****************************************************************************
95 * Create: allocates Posterize video thread output method
96 *****************************************************************************
97 * This function allocates and initializes a Posterize vout method.
98 *****************************************************************************/
99 static int Create( vlc_object_t *p_this )
101 filter_t *p_filter = (filter_t *)p_this;
102 filter_sys_t *p_sys;
104 switch( p_filter->fmt_in.video.i_chroma )
106 CASE_PLANAR_YUV_SQUARE
107 break;
108 CASE_PACKED_YUV_422
109 break;
110 case VLC_CODEC_RGB24:
111 break;
112 case VLC_CODEC_RGB32:
113 break;
114 default:
115 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
116 (char*)&(p_filter->fmt_in.video.i_chroma) );
117 return VLC_EGENERIC;
120 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
122 msg_Err( p_filter, "Input and output chromas don't match" );
123 return VLC_EGENERIC;
126 /* Allocate structure */
127 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
128 if( p_filter->p_sys == NULL )
129 return VLC_ENOMEM;
131 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
132 p_filter->p_cfg );
133 atomic_init( &p_sys->i_level,
134 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "level" ) );
136 var_AddCallback( p_filter, CFG_PREFIX "level", FilterCallback, p_sys );
138 p_filter->pf_video_filter = Filter;
140 return VLC_SUCCESS;
143 /*****************************************************************************
144 * Destroy: destroy Posterize video thread output method
145 *****************************************************************************
146 * Terminate an output method created by PosterizeCreateOutputMethod
147 *****************************************************************************/
148 static void Destroy( vlc_object_t *p_this )
150 filter_t *p_filter = (filter_t *)p_this;
151 filter_sys_t *p_sys = p_filter->p_sys;
153 var_DelCallback( p_filter, CFG_PREFIX "level", FilterCallback, p_sys );
154 free( p_sys );
157 /*****************************************************************************
158 * Render: displays previously rendered output
159 *****************************************************************************
160 * This function send the currently rendered image to Posterize image, waits
161 * until it is displayed and switch the two rendering buffers, preparing next
162 * frame.
163 *****************************************************************************/
164 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
166 picture_t *p_outpic;
168 if( !p_pic ) return NULL;
170 filter_sys_t *p_sys = p_filter->p_sys;
171 int level = atomic_load( &p_sys->i_level );
173 p_outpic = filter_NewPicture( p_filter );
174 if( !p_outpic )
176 msg_Warn( p_filter, "can't get output picture" );
177 picture_Release( p_pic );
178 return NULL;
181 switch( p_pic->format.i_chroma )
183 case VLC_CODEC_RGB24:
184 RVPosterize( p_pic, p_outpic, false, level );
185 break;
186 case VLC_CODEC_RGB32:
187 RVPosterize( p_pic, p_outpic, true, level );
188 break;
189 CASE_PLANAR_YUV_SQUARE
190 PlanarYUVPosterize( p_pic, p_outpic, level );
191 break;
192 CASE_PACKED_YUV_422
193 PackedYUVPosterize( p_pic, p_outpic, level );
194 break;
195 default:
196 vlc_assert_unreachable();
199 return CopyInfoAndRelease( p_outpic, p_pic );
202 /*****************************************************************************
203 * For a given level, calculates new posterized value for pixel whose value x
204 * is in range of 0-255
205 *****************************************************************************/
206 #define POSTERIZE_PIXEL(x, level) \
207 (((( x * level ) >> 8 ) * 255 ) / ( level - 1 ))
209 /*****************************************************************************
210 * PlanarYUVPosterize: Posterize one frame of the planar YUV video
211 *****************************************************************************
212 * This function posterizes one frame of the video by iterating through video
213 * lines. In every pass, start of Y, U and V planes is calculated and for
214 * every pixel we calculate new values of YUV values.
215 *****************************************************************************/
216 static void PlanarYUVPosterize( picture_t *p_pic, picture_t *p_outpic,
217 int i_level )
219 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_y, *p_line_end_y, *p_out_y,
220 *p_out_u, *p_out_v;
221 int i_current_line = 0;
223 p_in_y = p_pic->p[Y_PLANE].p_pixels;
224 p_in_end_y = p_in_y + p_pic->p[Y_PLANE].i_visible_lines
225 * p_pic->p[Y_PLANE].i_pitch;
226 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
228 /* iterate for every visible line in the frame */
229 while( p_in_y < p_in_end_y )
231 p_line_end_y = p_in_y + p_pic->p[Y_PLANE].i_visible_pitch;
232 /* calculate start of U plane line */
233 p_in_u = p_pic->p[U_PLANE].p_pixels
234 + p_pic->p[U_PLANE].i_pitch * ( i_current_line / 2 );
235 p_out_u = p_outpic->p[U_PLANE].p_pixels
236 + p_outpic->p[U_PLANE].i_pitch * ( i_current_line / 2 );
237 /* calculate start of V plane line */
238 p_in_v = p_pic->p[V_PLANE].p_pixels
239 + p_pic->p[V_PLANE].i_pitch * ( i_current_line / 2 );
240 p_out_v = p_outpic->p[V_PLANE].p_pixels
241 + p_outpic->p[V_PLANE].i_pitch * ( i_current_line / 2 );
242 /* iterate for every two pixels in line */
243 while( p_in_y < p_line_end_y )
245 uint8_t y1, y2, u, v;
246 uint8_t posterized_y1, posterized_y2, posterized_u, posterized_v;
247 /* retrieve original YUV values */
248 y1 = *p_in_y++;
249 y2 = *p_in_y++;
250 u = *p_in_u++;
251 v = *p_in_v++;
252 /* do posterization */
253 YuvPosterization( &posterized_y1, &posterized_y2, &posterized_u,
254 &posterized_v, y1, y2, u, v, i_level );
255 /* put posterized valued */
256 *p_out_y++ = posterized_y1;
257 *p_out_y++ = posterized_y2;
258 *p_out_u++ = posterized_u;
259 *p_out_v++ = posterized_v;
261 p_in_y += p_pic->p[Y_PLANE].i_pitch
262 - p_pic->p[Y_PLANE].i_visible_pitch;
263 p_out_y += p_outpic->p[Y_PLANE].i_pitch
264 - p_outpic->p[Y_PLANE].i_visible_pitch;
265 i_current_line++;
269 /*****************************************************************************
270 * PackedYUVPosterize: Posterize one frame of the packed YUV video
271 *****************************************************************************
272 * This function posterizes one frame of the video by iterating through video
273 * lines. In every pass, we calculate new values for pixels (UYVY, VYUY, YUYV
274 * and YVYU formats are supported)
275 *****************************************************************************/
276 static void PackedYUVPosterize( picture_t *p_pic, picture_t *p_outpic, int i_level )
278 uint8_t *p_in, *p_in_end, *p_line_end, *p_out;
279 uint8_t y1, y2, u, v;
281 p_in = p_pic->p[0].p_pixels;
282 p_in_end = p_in + p_pic->p[0].i_visible_lines
283 * p_pic->p[0].i_pitch;
284 p_out = p_outpic->p[0].p_pixels;
286 while( p_in < p_in_end )
288 p_line_end = p_in + p_pic->p[0].i_visible_pitch;
289 while( p_in < p_line_end )
291 uint8_t posterized_y1, posterized_y2, posterized_u, posterized_v;
292 /* extract proper pixel values */
293 switch( p_pic->format.i_chroma )
295 case VLC_CODEC_UYVY:
296 u = *p_in++;
297 y1 = *p_in++;
298 v = *p_in++;
299 y2 = *p_in++;
300 break;
301 case VLC_CODEC_VYUY:
302 v = *p_in++;
303 y1 = *p_in++;
304 u = *p_in++;
305 y2 = *p_in++;
306 break;
307 case VLC_CODEC_YUYV:
308 y1 = *p_in++;
309 u = *p_in++;
310 y2 = *p_in++;
311 v = *p_in++;
312 break;
313 case VLC_CODEC_YVYU:
314 y1 = *p_in++;
315 v = *p_in++;
316 y2 = *p_in++;
317 u = *p_in++;
318 break;
319 default:
320 vlc_assert_unreachable();
322 /* do posterization */
323 YuvPosterization( &posterized_y1, &posterized_y2, &posterized_u,
324 &posterized_v, y1, y2, u, v, i_level );
325 /* put posterized values in proper place */
326 switch( p_pic->format.i_chroma )
328 case VLC_CODEC_UYVY:
329 *p_out++ = posterized_u;
330 *p_out++ = posterized_y1;
331 *p_out++ = posterized_v;
332 *p_out++ = posterized_y2;
333 break;
334 case VLC_CODEC_VYUY:
335 *p_out++ = posterized_v;
336 *p_out++ = posterized_y1;
337 *p_out++ = posterized_u;
338 *p_out++ = posterized_y2;
339 break;
340 case VLC_CODEC_YUYV:
341 *p_out++ = posterized_y1;
342 *p_out++ = posterized_u;
343 *p_out++ = posterized_y2;
344 *p_out++ = posterized_v;
345 break;
346 case VLC_CODEC_YVYU:
347 *p_out++ = posterized_y1;
348 *p_out++ = posterized_v;
349 *p_out++ = posterized_y2;
350 *p_out++ = posterized_u;
351 break;
352 default:
353 vlc_assert_unreachable();
356 p_in += p_pic->p[0].i_pitch - p_pic->p[0].i_visible_pitch;
357 p_out += p_outpic->p[0].i_pitch
358 - p_outpic->p[0].i_visible_pitch;
362 /*****************************************************************************
363 * RVPosterize: Posterize one frame of the RV24/RV32 video
364 *****************************************************************************
365 * This function posterizes one frame of the video by iterating through video
366 * lines and calculating new values for every byte in chunks of 3 (RV24) or
367 * 4 (RV32) bytes
368 *****************************************************************************/
369 static void RVPosterize( picture_t *p_pic, picture_t *p_outpic,
370 bool rv32, int level )
372 uint8_t *p_in, *p_in_end, *p_line_end, *p_out, pixel;
374 p_in = p_pic->p[0].p_pixels;
375 p_in_end = p_in + p_pic->p[0].i_visible_lines
376 * p_pic->p[0].i_pitch;
377 p_out = p_outpic->p[0].p_pixels;
379 while( p_in < p_in_end )
381 p_line_end = p_in + p_pic->p[0].i_visible_pitch;
382 while( p_in < p_line_end )
384 pixel = *p_in++;
385 *p_out++ = POSTERIZE_PIXEL( pixel, level );
386 pixel = *p_in++;
387 *p_out++ = POSTERIZE_PIXEL( pixel, level );
388 pixel = *p_in++;
389 *p_out++ = POSTERIZE_PIXEL( pixel, level );
390 /* for rv32 we take 4 chunks at the time */
391 if ( rv32 )
393 pixel = *p_in++;
394 *p_out++ = POSTERIZE_PIXEL( pixel, level );
397 p_in += p_pic->p[0].i_pitch - p_pic->p[0].i_visible_pitch;
398 p_out += p_outpic->p[0].i_pitch
399 - p_outpic->p[0].i_visible_pitch;
403 /*****************************************************************************
404 * YuvPosterization: Lowers the color depth of YUV color space
405 *****************************************************************************
406 * This function lowers the color level of YUV color space to specified level
407 * by converting YUV color values to theirs RGB equivalents, calculates new
408 * values and then converts RGB values to YUV values again.
409 *****************************************************************************/
410 static void YuvPosterization( uint8_t* posterized_y1, uint8_t* posterized_y2,
411 uint8_t* posterized_u, uint8_t* posterized_v,
412 uint8_t y1, uint8_t y2, uint8_t u, uint8_t v,
413 int i_level ) {
414 int r1, g1, b1; /* for y1 new value */
415 int r2, b2, g2; /* for y2 new value */
416 int r3, g3, b3; /* for new values of u and v */
417 /* fist convert YUV -> RGB */
418 yuv_to_rgb( &r1, &g1, &b1, y1, u, v );
419 yuv_to_rgb( &r2, &g2, &b2, y1, u, v );
420 yuv_to_rgb( &r3, &g3, &b3, ( y1 + y2 ) / 2, u, v );
421 /* round RGB values to specified posterize level */
422 r1 = POSTERIZE_PIXEL( r1, i_level );
423 g1 = POSTERIZE_PIXEL( g1, i_level );
424 b1 = POSTERIZE_PIXEL( b1, i_level );
425 r2 = POSTERIZE_PIXEL( r2, i_level );
426 g2 = POSTERIZE_PIXEL( g2, i_level );
427 b2 = POSTERIZE_PIXEL( b2, i_level );
428 r3 = POSTERIZE_PIXEL( r3, i_level );
429 g3 = POSTERIZE_PIXEL( g3, i_level );
430 b3 = POSTERIZE_PIXEL( b3, i_level );
431 /* convert from calculated RGB -> YUV */
432 *posterized_y1 = ( ( 66 * r1 + 129 * g1 + 25 * b1 + 128 ) >> 8 ) + 16;
433 *posterized_y2 = ( ( 66 * r2 + 129 * g2 + 25 * b2 + 128 ) >> 8 ) + 16;
434 *posterized_u = ( ( -38 * r3 - 74 * g3 + 112 * b3 + 128 ) >> 8 ) + 128;
435 *posterized_v = ( ( 112 * r3 - 94 * g3 - 18 * b3 + 128 ) >> 8 ) + 128;
438 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
439 vlc_value_t oldval, vlc_value_t newval, void *p_data )
441 (void)p_this; (void)oldval;
442 filter_sys_t *p_sys = p_data;
444 if( !strcmp( psz_var, CFG_PREFIX "level" ) )
445 atomic_store( &p_sys->i_level, newval.i_int );
447 return VLC_SUCCESS;