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