]> git.sesse.net Git - vlc/blob - modules/video_filter/audiobargraph_v.c
Source files must not be executable.
[vlc] / modules / video_filter / audiobargraph_v.c
1 /*****************************************************************************
2  * audiobargraph_v.c : audiobargraph video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2006 the VideoLAN team
5  *
6  * Authors: Clement CHESNIN <clement.chesnin@gmail.com>
7  *          Philippe COENT <philippe.coent@tdf.fr>
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 #include <assert.h>
32 #include <string.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37
38 #include <vlc_image.h>
39 #include <vlc_osd.h>
40
41 #ifdef LoadImage
42 #   undef LoadImage
43 #endif
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48  
49 #define I_VALUES_TEXT N_("Value of the audio channels levels")
50 #define I_VALUES_LONGTEXT N_("Value of the audio level of each channels between 0 and 1" \
51     "Each level should be separated with ':'.")
52 #define POSX_TEXT N_("X coordinate")
53 #define POSX_LONGTEXT N_("X coordinate of the bargraph." )
54 #define POSY_TEXT N_("Y coordinate")
55 #define POSY_LONGTEXT N_("Y coordinate of the bargraph." )
56 #define TRANS_TEXT N_("Transparency of the bargraph")
57 #define TRANS_LONGTEXT N_("Bargraph transparency value " \
58   "(from 0 for full transparency to 255 for full opacity)." )
59 #define POS_TEXT N_("Bargraph position")
60 #define POS_LONGTEXT N_( \
61   "Enforce the bargraph position on the video " \
62   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
63   "also use combinations of these values, eg 6 = top-right).")
64 #define ALARM_TEXT N_("Alarm")
65 #define ALARM_LONGTEXT N_("Signals a silence and displays and alert " \
66                 "(0=no alarm, 1=alarm).")
67 #define BARWIDTH_TEXT N_("Bar width in pixel (default : 10)")
68 #define BARWIDTH_LONGTEXT N_("Width in pixel of each bar in the BarGraph to be displayed " \
69                 "(default : 10).")
70
71 #define CFG_PREFIX "audiobargraph_v-"
72
73 static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
74 static const char *const ppsz_pos_descriptions[] =
75 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
76   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
77
78 static int  OpenSub  ( vlc_object_t * );
79 static int  OpenVideo( vlc_object_t * );
80 static void Close    ( vlc_object_t * );
81
82 vlc_module_begin ()
83
84     set_category( CAT_VIDEO )
85     set_subcategory( SUBCAT_VIDEO_SUBPIC )
86
87     set_capability( "sub filter", 0 )
88     set_callbacks( OpenSub, Close )
89     set_description( N_("Audio Bar Graph Video sub filter") )
90     set_shortname( N_("Audio Bar Graph Video") )
91     add_shortcut( "audiobargraph_v" )
92
93     add_string( CFG_PREFIX "i_values", NULL, NULL, I_VALUES_TEXT, I_VALUES_LONGTEXT, false )
94     add_integer( CFG_PREFIX "x", 0, NULL, POSX_TEXT, POSX_LONGTEXT, true )
95     add_integer( CFG_PREFIX "y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, true )
96     add_integer_with_range( CFG_PREFIX "transparency", 255, 0, 255, NULL,
97         TRANS_TEXT, TRANS_LONGTEXT, false )
98     add_integer( CFG_PREFIX "position", -1, NULL, POS_TEXT, POS_LONGTEXT, false )
99         change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL )
100     add_integer( CFG_PREFIX "alarm", 0, NULL, ALARM_TEXT, ALARM_LONGTEXT, true )
101     add_integer( CFG_PREFIX "barWidth", 10, NULL, BARWIDTH_TEXT, BARWIDTH_LONGTEXT, true )
102
103     /* video output filter submodule */
104     add_submodule ()
105     set_capability( "video filter2", 0 )
106     set_callbacks( OpenVideo, Close )
107     set_description( N_("Audio Bar Graph Video sub filter") )
108     add_shortcut( "audiobargraph_v" )
109 vlc_module_end ()
110
111
112 /*****************************************************************************
113  * Local prototypes
114  *****************************************************************************/
115
116 /*****************************************************************************
117  * Structure to hold the Bar Graph properties
118  ****************************************************************************/
119 typedef struct
120 {
121     int i_alpha;       /* -1 means use default alpha */
122     int nbChannels;
123     int *i_values;
124     picture_t *p_pic;
125     mtime_t date;
126     int scale;
127     int alarm;
128     int barWidth;
129
130 } BarGraph_t;
131
132 /**
133  * Private data holder
134  */
135 struct filter_sys_t
136 {
137     filter_t *p_blend;
138
139     vlc_mutex_t lock;
140     
141     BarGraph_t p_BarGraph;
142
143     int i_pos;
144     int i_pos_x;
145     int i_pos_y;
146     bool b_absolute;
147
148     /* On the fly control variable */
149     bool b_spu_update;
150 };
151
152 static const char *const ppsz_filter_options[] = {
153     "i_values", "x", "y", "transparency", "position", "alarm", "barWidth", NULL
154 };
155
156 static const char *const ppsz_filter_callbacks[] = {
157     "audiobargraph_v-i_values",
158     "audiobargraph_v-x",
159     "audiobargraph_v-y",
160     "audiobargraph_v-transparency",
161     "audiobargraph_v-position",
162     "audiobargraph_v-alarm",
163     "audiobargraph_v-barWidth",
164     NULL
165 };
166
167 static int OpenCommon( vlc_object_t *, bool b_sub );
168
169 static subpicture_t *FilterSub( filter_t *, mtime_t );
170 static picture_t    *FilterVideo( filter_t *, picture_t * );
171
172 static int BarGraphCallback( vlc_object_t *, char const *,
173                          vlc_value_t, vlc_value_t, void * );
174
175 static void LoadBarGraph( vlc_object_t *, BarGraph_t *);
176 void parse_i_values( BarGraph_t *p_BarGraph, char *i_values);
177
178 /**
179  * Open the sub filter
180  */
181 static int OpenSub( vlc_object_t *p_this )
182 {
183     return OpenCommon( p_this, true );
184 }
185
186 /**
187  * Open the video filter
188  */
189 static int OpenVideo( vlc_object_t *p_this )
190 {
191     return OpenCommon( p_this, false );
192 }
193
194 /**
195  * Common open function
196  */
197 static int OpenCommon( vlc_object_t *p_this, bool b_sub )
198 {
199     filter_t *p_filter = (filter_t *)p_this;
200     filter_sys_t *p_sys;
201     BarGraph_t *p_BarGraph;
202     char* i_values = NULL;
203
204     /* */
205     if( !b_sub && !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) )
206     {
207         msg_Err( p_filter, "Input and output format does not match" );
208         return VLC_EGENERIC;
209     }
210
211
212     /* */
213     p_filter->p_sys = p_sys = malloc( sizeof( *p_sys ) );
214     if( !p_sys )
215         return VLC_ENOMEM;
216     p_BarGraph = &(p_sys->p_BarGraph);
217
218     /* */
219     p_sys->p_blend = NULL;
220     if( !b_sub )
221     {
222
223         p_sys->p_blend = filter_NewBlend( VLC_OBJECT(p_filter),
224                                           &p_filter->fmt_in.video );
225         if( !p_sys->p_blend )
226         {
227             //free( p_BarGraph );
228             free( p_sys );
229             return VLC_EGENERIC;
230         }
231     }
232
233     /* */
234     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
235                        p_filter->p_cfg );
236
237     /* create and initialize variables */
238     p_sys->i_pos = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-position" );
239     p_sys->i_pos_x = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-x" );
240     p_sys->i_pos_y = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-y" );
241     p_BarGraph->i_alpha = var_CreateGetIntegerCommand( p_filter,
242                                                         "audiobargraph_v-transparency" );
243     p_BarGraph->i_alpha = __MAX( __MIN( p_BarGraph->i_alpha, 255 ), 0 );
244     i_values = var_CreateGetStringCommand( p_filter, "audiobargraph_v-i_values" );
245     //p_BarGraph->nbChannels = 0;
246     //p_BarGraph->i_values = NULL;
247     parse_i_values(p_BarGraph, i_values);
248     p_BarGraph->alarm = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-alarm" );
249     p_BarGraph->barWidth = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-barWidth" );
250     p_BarGraph->scale = 400;
251
252     /* Ignore aligment if a position is given for video filter */
253     if( !b_sub && p_sys->i_pos_x >= 0 && p_sys->i_pos_y >= 0 )
254         p_sys->i_pos = 0;
255
256     vlc_mutex_init( &p_sys->lock );
257     LoadBarGraph( p_this, p_BarGraph );
258     p_sys->b_spu_update = true;
259
260     for( int i = 0; ppsz_filter_callbacks[i]; i++ )
261         var_AddCallback( p_filter, ppsz_filter_callbacks[i],
262                          BarGraphCallback, p_sys );
263
264     /* Misc init */
265     if( b_sub )
266     {
267         p_filter->pf_sub_filter = FilterSub;
268     }
269     else
270     {
271         p_filter->pf_video_filter = FilterVideo;
272     }
273
274     free( i_values );
275     return VLC_SUCCESS;
276 }
277
278 /**
279  * Common close function
280  */
281 static void Close( vlc_object_t *p_this )
282 {
283     filter_t *p_filter = (filter_t *)p_this;
284     filter_sys_t *p_sys = p_filter->p_sys;
285     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
286
287     for( int i = 0; ppsz_filter_callbacks[i]; i++ )
288         var_DelCallback( p_filter, ppsz_filter_callbacks[i],
289                          BarGraphCallback, p_sys );
290
291     if( p_sys->p_blend )
292         filter_DeleteBlend( p_sys->p_blend );
293
294     vlc_mutex_destroy( &p_sys->lock );
295     
296     if( p_BarGraph->p_pic )
297     {
298         picture_Release( p_BarGraph->p_pic );
299         p_BarGraph->p_pic = NULL;
300     }
301     free( p_BarGraph->i_values );
302     
303     free( p_sys );
304 }
305
306 /**
307  * Sub filter
308  */
309 static subpicture_t *FilterSub( filter_t *p_filter, mtime_t date )
310 {
311     filter_sys_t *p_sys = p_filter->p_sys;
312     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
313
314     subpicture_t *p_spu;
315     subpicture_region_t *p_region;
316     video_format_t fmt;
317     picture_t *p_pic;
318
319     vlc_mutex_lock( &p_sys->lock );
320     /* Basic test:  b_spu_update occurs on a dynamic change */
321     if( !p_sys->b_spu_update )
322     {
323         vlc_mutex_unlock( &p_sys->lock );
324         return 0;
325     }
326
327     p_pic = p_BarGraph->p_pic;
328
329     /* Allocate the subpicture internal data. */
330     p_spu = filter_NewSubpicture( p_filter );
331     if( !p_spu )
332         goto exit;
333
334     p_spu->b_absolute = p_sys->b_absolute;
335     p_spu->i_start = date;
336     p_spu->i_stop = 0;
337     p_spu->b_ephemer = true;
338
339     /* Send an empty subpicture to clear the display when needed */
340     if( !p_pic || !p_BarGraph->i_alpha )
341         goto exit;
342
343     /* Create new SPU region */
344     memset( &fmt, 0, sizeof(video_format_t) );
345     fmt.i_chroma = VLC_CODEC_YUVA;
346     fmt.i_aspect = VOUT_ASPECT_FACTOR;
347     fmt.i_sar_num = fmt.i_sar_den = 1;
348     fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
349     fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
350     fmt.i_x_offset = fmt.i_y_offset = 0;
351     p_region = subpicture_region_New( &fmt );
352     if( !p_region )
353     {
354         msg_Err( p_filter, "cannot allocate SPU region" );
355         p_filter->pf_sub_buffer_del( p_filter, p_spu );
356         p_spu = NULL;
357         goto exit;
358     }
359
360     /* */
361     picture_Copy( p_region->p_picture, p_pic );
362
363     /*  where to locate the bar graph: */
364     if( p_sys->i_pos < 0 )
365     {   /*  set to an absolute xy */
366         p_region->i_align = OSD_ALIGN_RIGHT | OSD_ALIGN_TOP;
367         p_spu->b_absolute = true;
368     }
369     else
370     {   /* set to one of the 9 relative locations */
371         p_region->i_align = p_sys->i_pos;
372         p_spu->b_absolute = false;
373     }
374
375     p_region->i_x = p_sys->i_pos_x;
376     p_region->i_y = p_sys->i_pos_y;
377
378     p_spu->p_region = p_region;
379
380     p_spu->i_alpha = p_BarGraph->i_alpha ;
381
382 exit:
383     vlc_mutex_unlock( &p_sys->lock );
384
385     return p_spu;
386 }
387
388 /**
389  * Video filter
390  */
391 static picture_t *FilterVideo( filter_t *p_filter, picture_t *p_src )
392 {
393     filter_sys_t *p_sys = p_filter->p_sys;
394     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
395
396     picture_t *p_dst = filter_NewPicture( p_filter );
397     if( !p_dst )
398         goto exit;
399
400     picture_Copy( p_dst, p_src );
401
402     /* */
403     vlc_mutex_lock( &p_sys->lock );
404
405     /* */
406     const picture_t *p_pic = p_BarGraph->p_pic;
407     if( p_pic )
408     {
409         const video_format_t *p_fmt = &p_pic->format;
410         const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
411         const int i_dst_h = p_filter->fmt_out.video.i_visible_height;
412
413         if( p_sys->i_pos )
414         {
415             if( p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM )
416             {
417                 p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
418             }
419             else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_TOP) )
420             {
421                 p_sys->i_pos_y = ( i_dst_h - p_fmt->i_visible_height ) / 2;
422             }
423             else
424             {
425                 p_sys->i_pos_y = 0;
426             }
427
428             if( p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT )
429             {
430                 p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
431             }
432             else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT) )
433             {
434                 p_sys->i_pos_x = ( i_dst_w - p_fmt->i_visible_width ) / 2;
435             }
436             else
437             {
438                 p_sys->i_pos_x = 0;
439             }
440         }
441
442         /* */
443         const int i_alpha = p_BarGraph->i_alpha;
444         if( filter_ConfigureBlend( p_sys->p_blend, i_dst_w, i_dst_h, p_fmt ) ||
445             filter_Blend( p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
446                           p_pic, i_alpha ) )
447         {
448             msg_Err( p_filter, "failed to blend a picture" );
449         }
450     }
451     vlc_mutex_unlock( &p_sys->lock );
452
453 exit:
454     picture_Release( p_src );
455     return p_dst;
456 }
457
458 /*****************************************************************************
459  * Callback to update params on the fly
460  *****************************************************************************/
461 static int BarGraphCallback( vlc_object_t *p_this, char const *psz_var,
462                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
463 {
464     VLC_UNUSED(oldval);
465     filter_sys_t *p_sys = (filter_sys_t *)p_data;
466     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
467     char* i_values;
468     char* res = NULL;
469
470     vlc_mutex_lock( &p_sys->lock );
471     if ( !strcmp( psz_var, "audiobargraph_v-x" ) )
472     {
473         p_sys->i_pos_x = newval.i_int;
474     }
475     else if ( !strcmp( psz_var, "audiobargraph_v-y" ) )
476     {
477         p_sys->i_pos_y = newval.i_int;
478     }
479     else if ( !strcmp( psz_var, "audiobargraph_v-position" ) )
480     {
481         p_sys->i_pos = newval.i_int;
482     }
483     else if ( !strcmp( psz_var, "audiobargraph_v-transparency" ) )
484     {
485         p_BarGraph->i_alpha = __MAX( __MIN( newval.i_int, 255 ), 0 );
486     }
487     else if ( !strcmp( psz_var, "audiobargraph_v-i_values" ) )
488     {
489         if( p_BarGraph->p_pic )
490         {
491             picture_Release( p_BarGraph->p_pic );
492             p_BarGraph->p_pic = NULL;
493         }
494         i_values = strdup( newval.psz_string );
495         free(p_BarGraph->i_values);
496         //p_BarGraph->i_values = NULL;
497         //p_BarGraph->nbChannels = 0;
498         // in case many answer are received at the same time, only keep one
499         res = strchr(i_values, '@');
500         if (res)
501             *res = 0;
502         parse_i_values( p_BarGraph, i_values);
503         LoadBarGraph(p_this,p_BarGraph);
504     }
505     else if ( !strcmp( psz_var, "audiobargraph_v-alarm" ) )
506     {
507         if( p_BarGraph->p_pic )
508         {
509             picture_Release( p_BarGraph->p_pic );
510             p_BarGraph->p_pic = NULL;
511         }
512         p_BarGraph->alarm = newval.i_int;
513         LoadBarGraph(p_this,p_BarGraph);
514     }
515     else if ( !strcmp( psz_var, "audiobargraph_v-barWidth" ) )
516     {
517         if( p_BarGraph->p_pic )
518         {
519             picture_Release( p_BarGraph->p_pic );
520             p_BarGraph->p_pic = NULL;
521         }
522         p_BarGraph->barWidth = newval.i_int;
523         LoadBarGraph(p_this,p_BarGraph);
524     }
525     p_sys->b_spu_update = true;
526     vlc_mutex_unlock( &p_sys->lock );
527
528     return VLC_SUCCESS;
529 }
530
531 /*****************************************************************************
532  * LoadImage: creates and returns the bar graph image
533  *****************************************************************************/
534 static picture_t *LoadImage( vlc_object_t *p_this, int nbChannels, int* i_values, int scale, int alarm, int barWidth)
535 {
536     VLC_UNUSED(p_this);
537     picture_t *p_pic;
538     int i,j;
539     int i_width = 0;
540     int i_line;
541     int moinsTrois, moinsCinq, moinsSept, moinsDix, moinsVingt;
542     
543     if (nbChannels == 0) {
544         i_width = 20;
545     } else {
546         i_width = 2 * nbChannels * barWidth + 10;
547     }
548     
549     moinsTrois = 0.71*scale + 20;
550     moinsCinq = 0.56*scale + 20;
551     moinsSept = 0.45*scale + 20;
552     moinsDix = 0.32*scale + 20;
553     moinsVingt = 0.1*scale + 20;
554     
555     p_pic = picture_New(VLC_FOURCC('Y','U','V','A'), i_width+20, scale+30, VOUT_ASPECT_FACTOR * (i_width+20)/(scale+30));
556     
557     // blacken the whole picture
558     for( i = 0 ; i < p_pic->i_planes ; i++ )
559     {
560         memset( p_pic->p[i].p_pixels, 0x00,
561                 p_pic->p[i].i_visible_lines * p_pic->p[i].i_pitch );
562     }
563     
564     // side bar
565     for ( i_line = 20; i_line < scale+20; i_line++ ) {
566     
567 #define DrawPointsBlack(a,b) {\
568         for (i=a; i<b; i++) {\
569             *(p_pic->p[0].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[0].i_pitch + i ) = 0x00; \
570             *(p_pic->p[1].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[1].i_pitch + i ) = 128; \
571             *(p_pic->p[2].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[2].i_pitch + i ) = 128; \
572             *(p_pic->p[3].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[3].i_pitch + i ) = 0xFF; \
573         }\
574     }
575 #define DrawPointsWhite(a,b) {\
576         for (i=a; i<b; i++) {\
577             *(p_pic->p[0].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[0].i_pitch + i ) = 0xFF;\
578             *(p_pic->p[1].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[1].i_pitch + i ) = 128;\
579             *(p_pic->p[2].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[2].i_pitch + i ) = 128;\
580             *(p_pic->p[3].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[3].i_pitch + i ) = 0xFF; \
581         }\
582     }    
583         
584         // vertical line
585         DrawPointsBlack(20,22);
586         DrawPointsWhite(22,24);
587     
588         // -3dB
589         if (i_line == moinsTrois - 2) {
590             // 3
591             DrawPointsBlack(16,19);
592         }
593         if (i_line == moinsTrois - 1) {
594             // 3
595             DrawPointsBlack(18,19);
596             // limit
597             DrawPointsWhite(24,27);
598         }
599         if (i_line == moinsTrois) {
600             // 3
601             DrawPointsBlack(16,19);
602             // limit
603             DrawPointsBlack(24,27);
604         }
605         if (i_line == moinsTrois + 1) {
606             // 3
607             DrawPointsBlack(18,19);
608             // limit
609             DrawPointsBlack(24,27);
610         }
611         if (i_line == moinsTrois + 2) {
612             // 3
613             DrawPointsBlack(16,19);
614         }
615         
616         // -5dB
617         if (i_line == moinsCinq - 2) {
618             // 5
619             DrawPointsBlack(16,19);
620         }
621         if (i_line == moinsCinq - 1) {
622             // 5
623             DrawPointsBlack(18,19);
624             // limit
625             DrawPointsWhite(24,27);
626         }
627         if (i_line == moinsCinq) {
628             // 5
629             DrawPointsBlack(16,19);
630             // limit
631             DrawPointsBlack(24,27);
632         }
633         if (i_line == moinsCinq + 1) {
634             // 5
635             DrawPointsBlack(16,17);
636             // limit
637             DrawPointsBlack(24,27);
638         }
639         if (i_line == moinsCinq + 2) {
640             // 5
641             DrawPointsBlack(16,19);
642         }
643         
644         // -7dB
645         if (i_line == moinsSept - 2) {
646             // 7
647             DrawPointsBlack(18,19);
648         }
649         if (i_line == moinsSept - 1) {
650             // 7
651             DrawPointsBlack(18,19);
652             // limit
653             DrawPointsWhite(24,27);
654         }
655         if (i_line == moinsSept) {
656             // 7
657             DrawPointsBlack(18,19);
658             // limit
659             DrawPointsBlack(24,27);
660         }
661         if (i_line == moinsSept + 1) {
662             // 7
663             DrawPointsBlack(18,19);
664             // limit
665             DrawPointsBlack(24,27);
666         }
667         if (i_line == moinsSept + 2) {
668             // 7
669             DrawPointsBlack(16,19);
670         }
671         
672         
673         // -10dB
674         if (i_line == moinsDix - 2) {
675             // 1
676             DrawPointsBlack(14,15);
677             // 0
678             DrawPointsBlack(16,19);
679         }
680         if (i_line == moinsDix - 1) {
681             // 1
682             DrawPointsBlack(14,15);
683             // 0
684             DrawPointsBlack(16,17);
685             DrawPointsBlack(18,19);
686             // limit
687             DrawPointsWhite(24,27);
688         }
689         if (i_line == moinsDix) {
690             // 1
691             DrawPointsBlack(14,15);
692             // 0
693             DrawPointsBlack(16,17);
694             DrawPointsBlack(18,19);
695             // limit
696             DrawPointsBlack(24,27);
697         }
698         if (i_line == moinsDix + 1) {
699             // 1
700             DrawPointsBlack(14,15);
701             // 0
702             DrawPointsBlack(16,17);
703             DrawPointsBlack(18,19);
704             // limit
705             DrawPointsBlack(24,27);
706         }
707         if (i_line == moinsDix + 2) {
708             // 1
709             DrawPointsBlack(14,15);
710             // 0
711             DrawPointsBlack(16,19);
712         }
713         
714         // -20dB
715         if (i_line == moinsVingt - 2) {
716             // 2
717             DrawPointsBlack(12,15);
718             // 0
719             DrawPointsBlack(16,19);
720         }
721         if (i_line == moinsVingt - 1) {
722             // 2
723             DrawPointsBlack(12,13);
724             // 0
725             DrawPointsBlack(16,17);
726             DrawPointsBlack(18,19);
727             // limit
728             DrawPointsWhite(24,27);
729         }
730         if (i_line == moinsVingt) {
731             // 2
732             DrawPointsBlack(12,15);
733             // 0
734             DrawPointsBlack(16,17);
735             DrawPointsBlack(18,19);
736             // limit
737             DrawPointsBlack(24,27);
738         }
739         if (i_line == moinsVingt + 1) {
740             // 2
741             DrawPointsBlack(14,15);
742             // 0
743             DrawPointsBlack(16,17);
744             DrawPointsBlack(18,19);
745             // limit
746             DrawPointsBlack(24,27);
747         }
748         if (i_line == moinsVingt + 2) {
749             // 2
750             DrawPointsBlack(12,15);
751             // 0
752             DrawPointsBlack(16,19);
753         }
754         
755         
756     }
757     
758     // draw the bars and channel indicators
759     for (i=0; i<nbChannels; i++) {
760         for( j = barWidth+20 ; j < 2*barWidth+20; j++)
761         {
762             // channel indicators
763             for ( i_line = 12; i_line < 18; i_line++ ) {
764                 // white
765                 *(p_pic->p[0].p_pixels +
766                     (scale + 30 - i_line - 1) *
767                     p_pic->p[0].i_pitch +
768                     ( (2*i*barWidth)+j ) ) = 255;
769                 *(p_pic->p[1].p_pixels +
770                     (scale + 30 - i_line - 1) *
771                     p_pic->p[1].i_pitch +
772                     ( (2*i*barWidth)+j ) ) = 128;
773                 *(p_pic->p[2].p_pixels +
774                     (scale + 30 - i_line - 1) *
775                     p_pic->p[2].i_pitch +
776                     ( (2*i*barWidth)+j ) ) = 128;
777                 *(p_pic->p[3].p_pixels +
778                     (scale + 30 - i_line - 1) *
779                     p_pic->p[3].i_pitch +
780                     ( (2*i*barWidth)+j )) = 0xFF;
781             }
782             // bars
783             for( i_line = 20; i_line < i_values[i]+20; i_line++ )
784             {
785                 if (i_line < moinsDix) { // green if < -10 dB
786                     *(p_pic->p[0].p_pixels +
787                         (scale + 30 - i_line - 1) *
788                         p_pic->p[0].i_pitch +
789                         ( (2*i*barWidth)+j ) ) = 150;
790                     *(p_pic->p[1].p_pixels +
791                         (scale + 30 - i_line - 1) *
792                         p_pic->p[1].i_pitch +
793                         ( (2*i*barWidth)+j ) ) = 44;
794                     *(p_pic->p[2].p_pixels +
795                         (scale + 30 - i_line - 1) *
796                         p_pic->p[2].i_pitch +
797                         ( (2*i*barWidth)+j ) ) = 21;
798                     *(p_pic->p[3].p_pixels +
799                         (scale + 30 - i_line - 1) *
800                         p_pic->p[3].i_pitch +
801                         ( (2*i*barWidth)+j )) = 0xFF;
802                 } else if (i_line < moinsTrois) { // yellow if > -10dB and < -3dB
803                     *(p_pic->p[0].p_pixels +
804                         (scale + 30 - i_line - 1) *
805                         p_pic->p[0].i_pitch +
806                         ( (2*i*barWidth)+j ) ) = 226;
807                     *(p_pic->p[1].p_pixels +
808                         (scale + 30 - i_line - 1) *
809                         p_pic->p[1].i_pitch +
810                         ( (2*i*barWidth)+j ) ) = 1;
811                     *(p_pic->p[2].p_pixels +
812                         (scale + 30 - i_line - 1) *
813                         p_pic->p[2].i_pitch +
814                         ( (2*i*barWidth)+j ) ) = 148;
815                     *(p_pic->p[3].p_pixels +
816                         (scale + 30 - i_line - 1) *
817                         p_pic->p[3].i_pitch +
818                         ( (2*i*barWidth)+j )) = 0xFF;
819                 } else { // red if > -3 dB
820                     *(p_pic->p[0].p_pixels +
821                         (scale + 30 - i_line - 1) *
822                         p_pic->p[0].i_pitch +
823                         ( (2*i*barWidth)+j ) ) = 76;
824                     *(p_pic->p[1].p_pixels +
825                         (scale + 30 - i_line - 1) *
826                         p_pic->p[1].i_pitch +
827                         ( (2*i*barWidth)+j ) ) = 85;
828                     *(p_pic->p[2].p_pixels +
829                         (scale + 30 - i_line - 1) *
830                         p_pic->p[2].i_pitch +
831                         ( (2*i*barWidth)+j ) ) = 0xFF;
832                     *(p_pic->p[3].p_pixels +
833                         (scale + 30 - i_line - 1) *
834                         p_pic->p[3].i_pitch +
835                         ( (2*i*barWidth)+j )) = 0xFF;
836                 }
837             }
838         }
839     }
840     
841     
842     
843     if (alarm) {// draw the alarm square
844         // bottom
845         for ( i_line = 0; i_line < 10; i_line++ ) {
846             for (i=0; i<i_width+20; i++) {
847                 *(p_pic->p[0].p_pixels +
848                     (scale + 30 - i_line - 1) *
849                     p_pic->p[0].i_pitch + i ) = 76;
850                 *(p_pic->p[1].p_pixels +
851                     (scale + 30 - i_line - 1) *
852                     p_pic->p[1].i_pitch + i ) = 85;
853                 *(p_pic->p[2].p_pixels +
854                     (scale + 30 - i_line - 1) *
855                     p_pic->p[2].i_pitch + i ) = 0xFF;
856                 *(p_pic->p[3].p_pixels +
857                     (scale + 30 - i_line - 1) *
858                     p_pic->p[3].i_pitch + i ) = 0xFF;
859             }
860         }
861         // top
862         for ( i_line = scale+21; i_line < scale+30; i_line++ ) {
863             for (i=0; i<i_width+20; i++) {
864                 *(p_pic->p[0].p_pixels +
865                     (scale + 30 - i_line - 1) *
866                     p_pic->p[0].i_pitch + i ) = 76;
867                 *(p_pic->p[1].p_pixels +
868                     (scale + 30 - i_line - 1) *
869                     p_pic->p[1].i_pitch + i ) = 85;
870                 *(p_pic->p[2].p_pixels +
871                     (scale + 30 - i_line - 1) *
872                     p_pic->p[2].i_pitch + i ) = 0xFF;
873                 *(p_pic->p[3].p_pixels +
874                     (scale + 30 - i_line - 1) *
875                     p_pic->p[3].i_pitch + i ) = 0xFF;
876             }
877         }
878         // sides
879         for ( i_line = 9; i_line < scale+21; i_line++ ) {
880             for (i=0; i<10; i++) {
881                 *(p_pic->p[0].p_pixels +
882                     (scale + 30 - i_line - 1) *
883                     p_pic->p[0].i_pitch + i ) = 76;
884                 *(p_pic->p[1].p_pixels +
885                     (scale + 30 - i_line - 1) *
886                     p_pic->p[1].i_pitch + i ) = 85;
887                 *(p_pic->p[2].p_pixels +
888                     (scale + 30 - i_line - 1) *
889                     p_pic->p[2].i_pitch + i ) = 0xFF;
890                 *(p_pic->p[3].p_pixels +
891                     (scale + 30 - i_line - 1) *
892                     p_pic->p[3].i_pitch + i ) = 0xFF;
893             }
894             for (i=i_width+11; i<i_width+20; i++) {
895                 *(p_pic->p[0].p_pixels +
896                     (scale + 30 - i_line - 1) *
897                     p_pic->p[0].i_pitch + i ) = 76;
898                 *(p_pic->p[1].p_pixels +
899                     (scale + 30 - i_line - 1) *
900                     p_pic->p[1].i_pitch + i ) = 85;
901                 *(p_pic->p[2].p_pixels +
902                     (scale + 30 - i_line - 1) *
903                     p_pic->p[2].i_pitch + i ) = 0xFF;
904                 *(p_pic->p[3].p_pixels +
905                     (scale + 30 - i_line - 1) *
906                     p_pic->p[3].i_pitch + i ) = 0xFF;
907             }
908         }
909     }
910     
911
912     return p_pic;
913 }
914
915 /*****************************************************************************
916  * LoadBarGraph: loads the BarGraph images into memory
917  *****************************************************************************/
918 static void LoadBarGraph( vlc_object_t *p_this, BarGraph_t *p_BarGraph )
919 {
920
921     p_BarGraph->p_pic = LoadImage( p_this, p_BarGraph->nbChannels, p_BarGraph->i_values, p_BarGraph->scale, p_BarGraph->alarm, p_BarGraph->barWidth);
922     if( !p_BarGraph->p_pic )
923     {
924         msg_Warn( p_this, "error while creating picture" );
925     }
926
927 }
928
929 /*****************************************************************************
930  * parse_i_values : parse i_values parameter and store the corresponding values
931  *****************************************************************************/
932 void parse_i_values( BarGraph_t *p_BarGraph, char *i_values)
933 {
934     char* res = NULL;
935     char delim[] = ":";
936     char* tok;
937
938     p_BarGraph->nbChannels = 0;
939     p_BarGraph->i_values = NULL;
940     res = strtok_r(i_values, delim, &tok);
941     while (res != NULL) {
942         p_BarGraph->nbChannels++;
943         p_BarGraph->i_values = (int*)realloc(p_BarGraph->i_values, p_BarGraph->nbChannels*sizeof(int));
944         p_BarGraph->i_values[p_BarGraph->nbChannels-1] = __MAX( __MIN( atof(res)*p_BarGraph->scale, p_BarGraph->scale ), 0 );
945         res = strtok_r(NULL, delim, &tok);
946     }
947
948 }