]> git.sesse.net Git - vlc/blob - modules/video_filter/audiobargraph_v.c
Do not build crop video filter plugin.
[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_sar_num = fmt.i_sar_den = 1;
346     fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
347     fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
348     fmt.i_x_offset = fmt.i_y_offset = 0;
349     p_region = subpicture_region_New( &fmt );
350     if( !p_region )
351     {
352         msg_Err( p_filter, "cannot allocate SPU region" );
353         p_filter->pf_sub_buffer_del( p_filter, p_spu );
354         p_spu = NULL;
355         goto exit;
356     }
357
358     /* */
359     picture_Copy( p_region->p_picture, p_pic );
360
361     /*  where to locate the bar graph: */
362     if( p_sys->i_pos < 0 )
363     {   /*  set to an absolute xy */
364         p_region->i_align = OSD_ALIGN_RIGHT | OSD_ALIGN_TOP;
365         p_spu->b_absolute = true;
366     }
367     else
368     {   /* set to one of the 9 relative locations */
369         p_region->i_align = p_sys->i_pos;
370         p_spu->b_absolute = false;
371     }
372
373     p_region->i_x = p_sys->i_pos_x;
374     p_region->i_y = p_sys->i_pos_y;
375
376     p_spu->p_region = p_region;
377
378     p_spu->i_alpha = p_BarGraph->i_alpha ;
379
380 exit:
381     vlc_mutex_unlock( &p_sys->lock );
382
383     return p_spu;
384 }
385
386 /**
387  * Video filter
388  */
389 static picture_t *FilterVideo( filter_t *p_filter, picture_t *p_src )
390 {
391     filter_sys_t *p_sys = p_filter->p_sys;
392     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
393
394     picture_t *p_dst = filter_NewPicture( p_filter );
395     if( !p_dst )
396         goto exit;
397
398     picture_Copy( p_dst, p_src );
399
400     /* */
401     vlc_mutex_lock( &p_sys->lock );
402
403     /* */
404     const picture_t *p_pic = p_BarGraph->p_pic;
405     if( p_pic )
406     {
407         const video_format_t *p_fmt = &p_pic->format;
408         const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
409         const int i_dst_h = p_filter->fmt_out.video.i_visible_height;
410
411         if( p_sys->i_pos )
412         {
413             if( p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM )
414             {
415                 p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
416             }
417             else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_TOP) )
418             {
419                 p_sys->i_pos_y = ( i_dst_h - p_fmt->i_visible_height ) / 2;
420             }
421             else
422             {
423                 p_sys->i_pos_y = 0;
424             }
425
426             if( p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT )
427             {
428                 p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
429             }
430             else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT) )
431             {
432                 p_sys->i_pos_x = ( i_dst_w - p_fmt->i_visible_width ) / 2;
433             }
434             else
435             {
436                 p_sys->i_pos_x = 0;
437             }
438         }
439
440         /* */
441         const int i_alpha = p_BarGraph->i_alpha;
442         if( filter_ConfigureBlend( p_sys->p_blend, i_dst_w, i_dst_h, p_fmt ) ||
443             filter_Blend( p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
444                           p_pic, i_alpha ) )
445         {
446             msg_Err( p_filter, "failed to blend a picture" );
447         }
448     }
449     vlc_mutex_unlock( &p_sys->lock );
450
451 exit:
452     picture_Release( p_src );
453     return p_dst;
454 }
455
456 /*****************************************************************************
457  * Callback to update params on the fly
458  *****************************************************************************/
459 static int BarGraphCallback( vlc_object_t *p_this, char const *psz_var,
460                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
461 {
462     VLC_UNUSED(oldval);
463     filter_sys_t *p_sys = (filter_sys_t *)p_data;
464     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
465     char* i_values;
466     char* res = NULL;
467
468     vlc_mutex_lock( &p_sys->lock );
469     if ( !strcmp( psz_var, "audiobargraph_v-x" ) )
470     {
471         p_sys->i_pos_x = newval.i_int;
472     }
473     else if ( !strcmp( psz_var, "audiobargraph_v-y" ) )
474     {
475         p_sys->i_pos_y = newval.i_int;
476     }
477     else if ( !strcmp( psz_var, "audiobargraph_v-position" ) )
478     {
479         p_sys->i_pos = newval.i_int;
480     }
481     else if ( !strcmp( psz_var, "audiobargraph_v-transparency" ) )
482     {
483         p_BarGraph->i_alpha = __MAX( __MIN( newval.i_int, 255 ), 0 );
484     }
485     else if ( !strcmp( psz_var, "audiobargraph_v-i_values" ) )
486     {
487         if( p_BarGraph->p_pic )
488         {
489             picture_Release( p_BarGraph->p_pic );
490             p_BarGraph->p_pic = NULL;
491         }
492         i_values = strdup( newval.psz_string );
493         free(p_BarGraph->i_values);
494         //p_BarGraph->i_values = NULL;
495         //p_BarGraph->nbChannels = 0;
496         // in case many answer are received at the same time, only keep one
497         res = strchr(i_values, '@');
498         if (res)
499             *res = 0;
500         parse_i_values( p_BarGraph, i_values);
501         LoadBarGraph(p_this,p_BarGraph);
502     }
503     else if ( !strcmp( psz_var, "audiobargraph_v-alarm" ) )
504     {
505         if( p_BarGraph->p_pic )
506         {
507             picture_Release( p_BarGraph->p_pic );
508             p_BarGraph->p_pic = NULL;
509         }
510         p_BarGraph->alarm = newval.i_int;
511         LoadBarGraph(p_this,p_BarGraph);
512     }
513     else if ( !strcmp( psz_var, "audiobargraph_v-barWidth" ) )
514     {
515         if( p_BarGraph->p_pic )
516         {
517             picture_Release( p_BarGraph->p_pic );
518             p_BarGraph->p_pic = NULL;
519         }
520         p_BarGraph->barWidth = newval.i_int;
521         LoadBarGraph(p_this,p_BarGraph);
522     }
523     p_sys->b_spu_update = true;
524     vlc_mutex_unlock( &p_sys->lock );
525
526     return VLC_SUCCESS;
527 }
528
529 /*****************************************************************************
530  * LoadImage: creates and returns the bar graph image
531  *****************************************************************************/
532 static picture_t *LoadImage( vlc_object_t *p_this, int nbChannels, int* i_values, int scale, int alarm, int barWidth)
533 {
534     VLC_UNUSED(p_this);
535     picture_t *p_pic;
536     int i,j;
537     int i_width = 0;
538     int i_line;
539     int moinsTrois, moinsCinq, moinsSept, moinsDix, moinsVingt;
540     
541     if (nbChannels == 0) {
542         i_width = 20;
543     } else {
544         i_width = 2 * nbChannels * barWidth + 10;
545     }
546     
547     moinsTrois = 0.71*scale + 20;
548     moinsCinq = 0.56*scale + 20;
549     moinsSept = 0.45*scale + 20;
550     moinsDix = 0.32*scale + 20;
551     moinsVingt = 0.1*scale + 20;
552     
553     p_pic = picture_New(VLC_FOURCC('Y','U','V','A'), i_width+20, scale+30, 1, 1);
554     
555     // blacken the whole picture
556     for( i = 0 ; i < p_pic->i_planes ; i++ )
557     {
558         memset( p_pic->p[i].p_pixels, 0x00,
559                 p_pic->p[i].i_visible_lines * p_pic->p[i].i_pitch );
560     }
561     
562     // side bar
563     for ( i_line = 20; i_line < scale+20; i_line++ ) {
564     
565 #define DrawPointsBlack(a,b) {\
566         for (i=a; i<b; i++) {\
567             *(p_pic->p[0].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[0].i_pitch + i ) = 0x00; \
568             *(p_pic->p[1].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[1].i_pitch + i ) = 128; \
569             *(p_pic->p[2].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[2].i_pitch + i ) = 128; \
570             *(p_pic->p[3].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[3].i_pitch + i ) = 0xFF; \
571         }\
572     }
573 #define DrawPointsWhite(a,b) {\
574         for (i=a; i<b; i++) {\
575             *(p_pic->p[0].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[0].i_pitch + i ) = 0xFF;\
576             *(p_pic->p[1].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[1].i_pitch + i ) = 128;\
577             *(p_pic->p[2].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[2].i_pitch + i ) = 128;\
578             *(p_pic->p[3].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[3].i_pitch + i ) = 0xFF; \
579         }\
580     }    
581         
582         // vertical line
583         DrawPointsBlack(20,22);
584         DrawPointsWhite(22,24);
585     
586         // -3dB
587         if (i_line == moinsTrois - 2) {
588             // 3
589             DrawPointsBlack(16,19);
590         }
591         if (i_line == moinsTrois - 1) {
592             // 3
593             DrawPointsBlack(18,19);
594             // limit
595             DrawPointsWhite(24,27);
596         }
597         if (i_line == moinsTrois) {
598             // 3
599             DrawPointsBlack(16,19);
600             // limit
601             DrawPointsBlack(24,27);
602         }
603         if (i_line == moinsTrois + 1) {
604             // 3
605             DrawPointsBlack(18,19);
606             // limit
607             DrawPointsBlack(24,27);
608         }
609         if (i_line == moinsTrois + 2) {
610             // 3
611             DrawPointsBlack(16,19);
612         }
613         
614         // -5dB
615         if (i_line == moinsCinq - 2) {
616             // 5
617             DrawPointsBlack(16,19);
618         }
619         if (i_line == moinsCinq - 1) {
620             // 5
621             DrawPointsBlack(18,19);
622             // limit
623             DrawPointsWhite(24,27);
624         }
625         if (i_line == moinsCinq) {
626             // 5
627             DrawPointsBlack(16,19);
628             // limit
629             DrawPointsBlack(24,27);
630         }
631         if (i_line == moinsCinq + 1) {
632             // 5
633             DrawPointsBlack(16,17);
634             // limit
635             DrawPointsBlack(24,27);
636         }
637         if (i_line == moinsCinq + 2) {
638             // 5
639             DrawPointsBlack(16,19);
640         }
641         
642         // -7dB
643         if (i_line == moinsSept - 2) {
644             // 7
645             DrawPointsBlack(18,19);
646         }
647         if (i_line == moinsSept - 1) {
648             // 7
649             DrawPointsBlack(18,19);
650             // limit
651             DrawPointsWhite(24,27);
652         }
653         if (i_line == moinsSept) {
654             // 7
655             DrawPointsBlack(18,19);
656             // limit
657             DrawPointsBlack(24,27);
658         }
659         if (i_line == moinsSept + 1) {
660             // 7
661             DrawPointsBlack(18,19);
662             // limit
663             DrawPointsBlack(24,27);
664         }
665         if (i_line == moinsSept + 2) {
666             // 7
667             DrawPointsBlack(16,19);
668         }
669         
670         
671         // -10dB
672         if (i_line == moinsDix - 2) {
673             // 1
674             DrawPointsBlack(14,15);
675             // 0
676             DrawPointsBlack(16,19);
677         }
678         if (i_line == moinsDix - 1) {
679             // 1
680             DrawPointsBlack(14,15);
681             // 0
682             DrawPointsBlack(16,17);
683             DrawPointsBlack(18,19);
684             // limit
685             DrawPointsWhite(24,27);
686         }
687         if (i_line == moinsDix) {
688             // 1
689             DrawPointsBlack(14,15);
690             // 0
691             DrawPointsBlack(16,17);
692             DrawPointsBlack(18,19);
693             // limit
694             DrawPointsBlack(24,27);
695         }
696         if (i_line == moinsDix + 1) {
697             // 1
698             DrawPointsBlack(14,15);
699             // 0
700             DrawPointsBlack(16,17);
701             DrawPointsBlack(18,19);
702             // limit
703             DrawPointsBlack(24,27);
704         }
705         if (i_line == moinsDix + 2) {
706             // 1
707             DrawPointsBlack(14,15);
708             // 0
709             DrawPointsBlack(16,19);
710         }
711         
712         // -20dB
713         if (i_line == moinsVingt - 2) {
714             // 2
715             DrawPointsBlack(12,15);
716             // 0
717             DrawPointsBlack(16,19);
718         }
719         if (i_line == moinsVingt - 1) {
720             // 2
721             DrawPointsBlack(12,13);
722             // 0
723             DrawPointsBlack(16,17);
724             DrawPointsBlack(18,19);
725             // limit
726             DrawPointsWhite(24,27);
727         }
728         if (i_line == moinsVingt) {
729             // 2
730             DrawPointsBlack(12,15);
731             // 0
732             DrawPointsBlack(16,17);
733             DrawPointsBlack(18,19);
734             // limit
735             DrawPointsBlack(24,27);
736         }
737         if (i_line == moinsVingt + 1) {
738             // 2
739             DrawPointsBlack(14,15);
740             // 0
741             DrawPointsBlack(16,17);
742             DrawPointsBlack(18,19);
743             // limit
744             DrawPointsBlack(24,27);
745         }
746         if (i_line == moinsVingt + 2) {
747             // 2
748             DrawPointsBlack(12,15);
749             // 0
750             DrawPointsBlack(16,19);
751         }
752         
753         
754     }
755     
756     // draw the bars and channel indicators
757     for (i=0; i<nbChannels; i++) {
758         for( j = barWidth+20 ; j < 2*barWidth+20; j++)
759         {
760             // channel indicators
761             for ( i_line = 12; i_line < 18; i_line++ ) {
762                 // white
763                 *(p_pic->p[0].p_pixels +
764                     (scale + 30 - i_line - 1) *
765                     p_pic->p[0].i_pitch +
766                     ( (2*i*barWidth)+j ) ) = 255;
767                 *(p_pic->p[1].p_pixels +
768                     (scale + 30 - i_line - 1) *
769                     p_pic->p[1].i_pitch +
770                     ( (2*i*barWidth)+j ) ) = 128;
771                 *(p_pic->p[2].p_pixels +
772                     (scale + 30 - i_line - 1) *
773                     p_pic->p[2].i_pitch +
774                     ( (2*i*barWidth)+j ) ) = 128;
775                 *(p_pic->p[3].p_pixels +
776                     (scale + 30 - i_line - 1) *
777                     p_pic->p[3].i_pitch +
778                     ( (2*i*barWidth)+j )) = 0xFF;
779             }
780             // bars
781             for( i_line = 20; i_line < i_values[i]+20; i_line++ )
782             {
783                 if (i_line < moinsDix) { // green if < -10 dB
784                     *(p_pic->p[0].p_pixels +
785                         (scale + 30 - i_line - 1) *
786                         p_pic->p[0].i_pitch +
787                         ( (2*i*barWidth)+j ) ) = 150;
788                     *(p_pic->p[1].p_pixels +
789                         (scale + 30 - i_line - 1) *
790                         p_pic->p[1].i_pitch +
791                         ( (2*i*barWidth)+j ) ) = 44;
792                     *(p_pic->p[2].p_pixels +
793                         (scale + 30 - i_line - 1) *
794                         p_pic->p[2].i_pitch +
795                         ( (2*i*barWidth)+j ) ) = 21;
796                     *(p_pic->p[3].p_pixels +
797                         (scale + 30 - i_line - 1) *
798                         p_pic->p[3].i_pitch +
799                         ( (2*i*barWidth)+j )) = 0xFF;
800                 } else if (i_line < moinsTrois) { // yellow if > -10dB and < -3dB
801                     *(p_pic->p[0].p_pixels +
802                         (scale + 30 - i_line - 1) *
803                         p_pic->p[0].i_pitch +
804                         ( (2*i*barWidth)+j ) ) = 226;
805                     *(p_pic->p[1].p_pixels +
806                         (scale + 30 - i_line - 1) *
807                         p_pic->p[1].i_pitch +
808                         ( (2*i*barWidth)+j ) ) = 1;
809                     *(p_pic->p[2].p_pixels +
810                         (scale + 30 - i_line - 1) *
811                         p_pic->p[2].i_pitch +
812                         ( (2*i*barWidth)+j ) ) = 148;
813                     *(p_pic->p[3].p_pixels +
814                         (scale + 30 - i_line - 1) *
815                         p_pic->p[3].i_pitch +
816                         ( (2*i*barWidth)+j )) = 0xFF;
817                 } else { // red if > -3 dB
818                     *(p_pic->p[0].p_pixels +
819                         (scale + 30 - i_line - 1) *
820                         p_pic->p[0].i_pitch +
821                         ( (2*i*barWidth)+j ) ) = 76;
822                     *(p_pic->p[1].p_pixels +
823                         (scale + 30 - i_line - 1) *
824                         p_pic->p[1].i_pitch +
825                         ( (2*i*barWidth)+j ) ) = 85;
826                     *(p_pic->p[2].p_pixels +
827                         (scale + 30 - i_line - 1) *
828                         p_pic->p[2].i_pitch +
829                         ( (2*i*barWidth)+j ) ) = 0xFF;
830                     *(p_pic->p[3].p_pixels +
831                         (scale + 30 - i_line - 1) *
832                         p_pic->p[3].i_pitch +
833                         ( (2*i*barWidth)+j )) = 0xFF;
834                 }
835             }
836         }
837     }
838     
839     
840     
841     if (alarm) {// draw the alarm square
842         // bottom
843         for ( i_line = 0; i_line < 10; i_line++ ) {
844             for (i=0; i<i_width+20; i++) {
845                 *(p_pic->p[0].p_pixels +
846                     (scale + 30 - i_line - 1) *
847                     p_pic->p[0].i_pitch + i ) = 76;
848                 *(p_pic->p[1].p_pixels +
849                     (scale + 30 - i_line - 1) *
850                     p_pic->p[1].i_pitch + i ) = 85;
851                 *(p_pic->p[2].p_pixels +
852                     (scale + 30 - i_line - 1) *
853                     p_pic->p[2].i_pitch + i ) = 0xFF;
854                 *(p_pic->p[3].p_pixels +
855                     (scale + 30 - i_line - 1) *
856                     p_pic->p[3].i_pitch + i ) = 0xFF;
857             }
858         }
859         // top
860         for ( i_line = scale+21; i_line < scale+30; i_line++ ) {
861             for (i=0; i<i_width+20; i++) {
862                 *(p_pic->p[0].p_pixels +
863                     (scale + 30 - i_line - 1) *
864                     p_pic->p[0].i_pitch + i ) = 76;
865                 *(p_pic->p[1].p_pixels +
866                     (scale + 30 - i_line - 1) *
867                     p_pic->p[1].i_pitch + i ) = 85;
868                 *(p_pic->p[2].p_pixels +
869                     (scale + 30 - i_line - 1) *
870                     p_pic->p[2].i_pitch + i ) = 0xFF;
871                 *(p_pic->p[3].p_pixels +
872                     (scale + 30 - i_line - 1) *
873                     p_pic->p[3].i_pitch + i ) = 0xFF;
874             }
875         }
876         // sides
877         for ( i_line = 9; i_line < scale+21; i_line++ ) {
878             for (i=0; i<10; i++) {
879                 *(p_pic->p[0].p_pixels +
880                     (scale + 30 - i_line - 1) *
881                     p_pic->p[0].i_pitch + i ) = 76;
882                 *(p_pic->p[1].p_pixels +
883                     (scale + 30 - i_line - 1) *
884                     p_pic->p[1].i_pitch + i ) = 85;
885                 *(p_pic->p[2].p_pixels +
886                     (scale + 30 - i_line - 1) *
887                     p_pic->p[2].i_pitch + i ) = 0xFF;
888                 *(p_pic->p[3].p_pixels +
889                     (scale + 30 - i_line - 1) *
890                     p_pic->p[3].i_pitch + i ) = 0xFF;
891             }
892             for (i=i_width+11; i<i_width+20; i++) {
893                 *(p_pic->p[0].p_pixels +
894                     (scale + 30 - i_line - 1) *
895                     p_pic->p[0].i_pitch + i ) = 76;
896                 *(p_pic->p[1].p_pixels +
897                     (scale + 30 - i_line - 1) *
898                     p_pic->p[1].i_pitch + i ) = 85;
899                 *(p_pic->p[2].p_pixels +
900                     (scale + 30 - i_line - 1) *
901                     p_pic->p[2].i_pitch + i ) = 0xFF;
902                 *(p_pic->p[3].p_pixels +
903                     (scale + 30 - i_line - 1) *
904                     p_pic->p[3].i_pitch + i ) = 0xFF;
905             }
906         }
907     }
908     
909
910     return p_pic;
911 }
912
913 /*****************************************************************************
914  * LoadBarGraph: loads the BarGraph images into memory
915  *****************************************************************************/
916 static void LoadBarGraph( vlc_object_t *p_this, BarGraph_t *p_BarGraph )
917 {
918
919     p_BarGraph->p_pic = LoadImage( p_this, p_BarGraph->nbChannels, p_BarGraph->i_values, p_BarGraph->scale, p_BarGraph->alarm, p_BarGraph->barWidth);
920     if( !p_BarGraph->p_pic )
921     {
922         msg_Warn( p_this, "error while creating picture" );
923     }
924
925 }
926
927 /*****************************************************************************
928  * parse_i_values : parse i_values parameter and store the corresponding values
929  *****************************************************************************/
930 void parse_i_values( BarGraph_t *p_BarGraph, char *i_values)
931 {
932     char* res = NULL;
933     char delim[] = ":";
934     char* tok;
935
936     p_BarGraph->nbChannels = 0;
937     p_BarGraph->i_values = NULL;
938     res = strtok_r(i_values, delim, &tok);
939     while (res != NULL) {
940         p_BarGraph->nbChannels++;
941         p_BarGraph->i_values = xrealloc(p_BarGraph->i_values,
942                                           p_BarGraph->nbChannels*sizeof(int));
943         p_BarGraph->i_values[p_BarGraph->nbChannels-1] = __MAX( __MIN( atof(res)*p_BarGraph->scale, p_BarGraph->scale ), 0 );
944         res = strtok_r(NULL, delim, &tok);
945     }
946
947 }