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