]> git.sesse.net Git - vlc/blob - modules/video_filter/audiobargraph_v.c
decoder: do not mix and match condidition variable and mutex pairings
[vlc] / modules / video_filter / audiobargraph_v.c
1 /*****************************************************************************
2  * audiobargraph_v.c : audiobargraph video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2006 VLC authors and VideoLAN
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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <string.h>
32 #include <math.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37
38 #include <vlc_image.h>
39
40 /*****************************************************************************
41  * Module descriptor
42  *****************************************************************************/
43
44 #define POSX_TEXT N_("X coordinate")
45 #define POSX_LONGTEXT N_("X coordinate of the bargraph.")
46 #define POSY_TEXT N_("Y coordinate")
47 #define POSY_LONGTEXT N_("Y coordinate of the bargraph.")
48 #define TRANS_TEXT N_("Transparency of the bargraph")
49 #define TRANS_LONGTEXT N_("Bargraph transparency value " \
50   "(from 0 for full transparency to 255 for full opacity).")
51 #define POS_TEXT N_("Bargraph position")
52 #define POS_LONGTEXT N_(\
53   "Enforce the bargraph position on the video " \
54   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
55   "also use combinations of these values, eg 6 = top-right).")
56 #define BARWIDTH_TEXT N_("Bar width in pixel (default : 10)")
57 #define BARWIDTH_LONGTEXT N_("Width in pixel of each bar in the BarGraph to be displayed " \
58                 "(default : 10).")
59
60 #define CFG_PREFIX "audiobargraph_v-"
61
62 static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
63 static const char *const ppsz_pos_descriptions[] =
64 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
65   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
66
67 static int  OpenSub  (vlc_object_t *);
68 static int  OpenVideo(vlc_object_t *);
69 static void Close    (vlc_object_t *);
70
71 vlc_module_begin ()
72
73     set_category(CAT_VIDEO)
74     set_subcategory(SUBCAT_VIDEO_SUBPIC)
75
76     set_capability("sub source", 0)
77     set_callbacks(OpenSub, Close)
78     set_description(N_("Audio Bar Graph Video sub source"))
79     set_shortname(N_("Audio Bar Graph Video"))
80     add_shortcut("audiobargraph_v")
81
82     add_obsolete_string(CFG_PREFIX "i_values")
83     add_integer(CFG_PREFIX "x", 0, POSX_TEXT, POSX_LONGTEXT, true)
84     add_integer(CFG_PREFIX "y", 0, POSY_TEXT, POSY_LONGTEXT, true)
85     add_integer_with_range(CFG_PREFIX "transparency", 255, 0, 255,
86         TRANS_TEXT, TRANS_LONGTEXT, false)
87     add_integer(CFG_PREFIX "position", -1, POS_TEXT, POS_LONGTEXT, false)
88         change_integer_list(pi_pos_values, ppsz_pos_descriptions)
89     add_obsolete_integer(CFG_PREFIX "alarm")
90     add_integer(CFG_PREFIX "barWidth", 10, BARWIDTH_TEXT, BARWIDTH_LONGTEXT, true)
91
92     /* video output filter submodule */
93     add_submodule ()
94     set_capability("video filter2", 0)
95     set_callbacks(OpenVideo, Close)
96     set_description(N_("Audio Bar Graph Video sub source"))
97     add_shortcut("audiobargraph_v")
98 vlc_module_end ()
99
100
101 /*****************************************************************************
102  * Local prototypes
103  *****************************************************************************/
104
105 /*****************************************************************************
106  * Structure to hold the Bar Graph properties
107  ****************************************************************************/
108 typedef struct
109 {
110     int i_alpha;       /* -1 means use default alpha */
111     int nbChannels;
112     int *i_values;
113     picture_t *p_pic;
114     mtime_t date;
115     int scale;
116     bool alarm;
117     int barWidth;
118
119 } BarGraph_t;
120
121 /**
122  * Private data holder
123  */
124 struct filter_sys_t
125 {
126     filter_t *p_blend;
127
128     vlc_mutex_t lock;
129
130     BarGraph_t p_BarGraph;
131
132     int i_pos;
133     int i_pos_x;
134     int i_pos_y;
135     bool b_absolute;
136
137     /* On the fly control variable */
138     bool b_spu_update;
139 };
140
141 static const char *const ppsz_filter_options[] = {
142     "x", "y", "transparency", "position", "barWidth", NULL
143 };
144
145 static const char *const ppsz_filter_callbacks[] = {
146     "audiobargraph_v-x",
147     "audiobargraph_v-y",
148     "audiobargraph_v-transparency",
149     "audiobargraph_v-position",
150     "audiobargraph_v-barWidth",
151     NULL
152 };
153
154 /*****************************************************************************
155  * IEC 268-18  Source: meterbridge
156  *****************************************************************************/
157 static float iec_scale(float dB)
158 {
159     if (dB < -70.0f)
160         return 0.0f;
161     if (dB < -60.0f)
162         return (dB + 70.0f) * 0.0025f;
163     if (dB < -50.0f)
164         return (dB + 60.0f) * 0.005f + 0.025f;
165     if (dB < -40.0f)
166         return (dB + 50.0f) * 0.0075f + 0.075f;
167     if (dB < -30.0f)
168         return (dB + 40.0f) * 0.015f + 0.15f;
169     if (dB < -20.0f)
170         return (dB + 30.0f) * 0.02f + 0.3f;
171     if (dB < -0.001f || dB > 0.001f)  /* if (dB < 0.0f) */
172         return (dB + 20.0f) * 0.025f + 0.5f;
173     return 1.0f;
174 }
175
176 /*****************************************************************************
177  * parse_i_values : parse i_values parameter and store the corresponding values
178  *****************************************************************************/
179 static void parse_i_values(BarGraph_t *p_BarGraph, char *i_values)
180 {
181     char delim[] = ":";
182     char* tok;
183
184     p_BarGraph->nbChannels = 0;
185     free(p_BarGraph->i_values);
186     p_BarGraph->i_values = NULL;
187     char *res = strtok_r(i_values, delim, &tok);
188     while (res != NULL) {
189         p_BarGraph->nbChannels++;
190         p_BarGraph->i_values = xrealloc(p_BarGraph->i_values,
191                                           p_BarGraph->nbChannels*sizeof(int));
192         float db = log10(atof(res)) * 20;
193         p_BarGraph->i_values[p_BarGraph->nbChannels-1] = VLC_CLIP(iec_scale(db)*p_BarGraph->scale, 0, p_BarGraph->scale);
194         res = strtok_r(NULL, delim, &tok);
195     }
196 }
197
198 /* Drawing */
199
200 static const uint8_t bright_red[4]   = { 76, 85, 0xff, 0xff };
201 static const uint8_t black[4] = { 0x00, 0x80, 0x80, 0xff };
202 static const uint8_t white[4] = { 0xff, 0x80, 0x80, 0xff };
203 static const uint8_t bright_green[4] = { 150, 44, 21, 0xff };
204 static const uint8_t bright_yellow[4] = { 226, 1, 148, 0xff };
205 static const uint8_t green[4] = { 74, 85, 74, 0xff };
206 static const uint8_t yellow[4] = { 112, 64, 138, 0xff };
207 static const uint8_t red[4] = { 37, 106, 191, 0xff };
208
209 static inline void DrawHLine(plane_t *p, int line, int col, const uint8_t color[4], int w)
210 {
211     for (int j = 0; j < 4; j++)
212         memset(&p[j].p_pixels[line * p[j].i_pitch + col], color[j], w);
213 }
214
215 static void Draw2VLines(plane_t *p, int scale, int col, const uint8_t color[4])
216 {
217     for (int i = 10; i < scale + 10; i++)
218         DrawHLine(p, i, col, color, 2);
219 }
220
221 static void DrawHLines(plane_t *p, int line, int col, const uint8_t color[4], int h, int w)
222 {
223     for (int i = line; i < line + h; i++)
224         DrawHLine(p, i, col, color, w);
225 }
226
227 static void DrawNumber(plane_t *p, int h, const uint8_t data[5], int l)
228 {
229     for (int i = 0; i < 5; i++) {
230         uint8_t x = data[i];
231         for (int j = 0; j < 7; j++) {
232             x <<= 1;
233             if (x & 0x80)
234                 DrawHLine(p, h - l + 2 - 1 - i, 12 + j, black, 1);
235         }
236     }
237 }
238 /*****************************************************************************
239  * Draw: creates and returns the bar graph image
240  *****************************************************************************/
241 static void Draw(BarGraph_t *b)
242 {
243     int nbChannels = b->nbChannels;
244     int scale      = b->scale;
245     int barWidth   = b->barWidth;
246
247     int w = 40;
248     if (nbChannels > 0)
249         w = 2 * nbChannels * barWidth + 30;
250     int h = scale + 30;
251
252     int level[6];
253     for (int i = 0; i < 6; i++)
254         level[i] = iec_scale(-(i+1) * 10) * scale + 20;
255
256     if (b->p_pic)
257         picture_Release(b->p_pic);
258     b->p_pic = picture_New(VLC_FOURCC('Y','U','V','A'), w, h, 1, 1);
259     if (!b->p_pic)
260         return;
261     picture_t *p_pic = b->p_pic;
262     plane_t *p = p_pic->p;
263
264     for (int i = 0 ; i < p_pic->i_planes ; i++)
265         memset(p[i].p_pixels, 0x00, p[i].i_visible_lines * p[i].i_pitch);
266
267     Draw2VLines(p, scale, 20, black);
268     Draw2VLines(p, scale, 22, white);
269
270     static const uint8_t pixmap[6][5] = {
271         { 0x17, 0x15, 0x15, 0x15, 0x17 },
272         { 0x77, 0x45, 0x75, 0x15, 0x77 },
273         { 0x77, 0x15, 0x75, 0x15, 0x77 },
274         { 0x17, 0x15, 0x75, 0x55, 0x57 },
275         { 0x77, 0x15, 0x75, 0x45, 0x77 },
276         { 0x77, 0x55, 0x75, 0x45, 0x77 },
277     };
278
279     for (int i = 0; i < 6; i++) {
280         DrawHLines(p, h - 1 - level[i] - 1, 24, white, 1, 3);
281         DrawHLines(p, h - 1 - level[i],     24, black, 2, 3);
282         DrawNumber(p, h, pixmap[i], level[i]);
283     }
284
285     int minus8  = iec_scale(- 8) * scale + 20;
286     int minus18 = iec_scale(-18) * scale + 20;
287     int *i_values  = b->i_values;
288     const uint8_t *indicator_color = b->alarm ? bright_red : black;
289
290     for (int i = 0; i < nbChannels; i++) {
291         int pi = 30 + i * (5 + barWidth);
292
293         DrawHLines(p, h - 20 - 1, pi, indicator_color, 8, barWidth);
294
295         for (int line = 20; line < i_values[i] + 20; line++) {
296             if (line < minus18)
297                 DrawHLines(p, h - line - 1, pi, bright_green, 1, barWidth);
298             else if (line < minus8)
299                 DrawHLines(p, h - line - 1, pi, bright_yellow, 1, barWidth);
300             else
301                 DrawHLines(p, h - line - 1, pi, bright_red, 1, barWidth);
302         }
303
304         for (int line = i_values[i] + 20; line < scale + 20; line++) {
305             if (line < minus18)
306                 DrawHLines(p, h - line - 1, pi, green, 1, barWidth);
307             else if (line < minus8)
308                 DrawHLines(p, h - line - 1, pi, yellow, 1, barWidth);
309             else
310                 DrawHLines(p, h - line - 1, pi, red, 1, barWidth);
311         }
312     }
313 }
314
315 /*****************************************************************************
316  * Callback to update params on the fly
317  *****************************************************************************/
318 static int BarGraphCallback(vlc_object_t *p_this, char const *psz_var,
319                          vlc_value_t oldval, vlc_value_t newval, void *p_data)
320 {
321     VLC_UNUSED(p_this); VLC_UNUSED(oldval);
322     filter_sys_t *p_sys = p_data;
323     BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
324     char* res = NULL;
325
326     vlc_mutex_lock(&p_sys->lock);
327     if (!strcmp(psz_var, CFG_PREFIX "x"))
328         p_sys->i_pos_x = newval.i_int;
329     else if (!strcmp(psz_var, CFG_PREFIX "y"))
330         p_sys->i_pos_y = newval.i_int;
331     else if (!strcmp(psz_var, CFG_PREFIX "position"))
332         p_sys->i_pos = newval.i_int;
333     else if (!strcmp(psz_var, CFG_PREFIX "transparency"))
334         p_BarGraph->i_alpha = VLC_CLIP(newval.i_int, 0, 255);
335     else if (!strcmp(psz_var, CFG_PREFIX "i_values")) {
336         char *psz = xstrdup(newval.psz_string ? newval.psz_string : "");
337         // in case many answer are received at the same time, only keep one
338         res = strchr(psz, '@');
339         if (res)
340             *res = '\0';
341         parse_i_values(p_BarGraph, psz);
342         free(psz);
343         Draw(p_BarGraph);
344     } else if (!strcmp(psz_var, CFG_PREFIX "alarm")) {
345         p_BarGraph->alarm = newval.b_bool;
346         Draw(p_BarGraph);
347     } else if (!strcmp(psz_var, CFG_PREFIX "barWidth")) {
348         p_BarGraph->barWidth = newval.i_int;
349         Draw(p_BarGraph);
350     }
351     p_sys->b_spu_update = true;
352     vlc_mutex_unlock(&p_sys->lock);
353
354     return VLC_SUCCESS;
355 }
356
357 /**
358  * Sub source
359  */
360 static subpicture_t *FilterSub(filter_t *p_filter, mtime_t date)
361 {
362     filter_sys_t *p_sys = p_filter->p_sys;
363     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
364
365     subpicture_t *p_spu;
366     subpicture_region_t *p_region;
367     video_format_t fmt;
368     picture_t *p_pic;
369
370     vlc_mutex_lock(&p_sys->lock);
371     /* Basic test:  b_spu_update occurs on a dynamic change */
372     if (!p_sys->b_spu_update) {
373         vlc_mutex_unlock(&p_sys->lock);
374         return NULL;
375     }
376
377     p_pic = p_BarGraph->p_pic;
378
379     /* Allocate the subpicture internal data. */
380     p_spu = filter_NewSubpicture(p_filter);
381     if (!p_spu)
382         goto exit;
383
384     p_spu->b_absolute = p_sys->b_absolute;
385     p_spu->i_start = date;
386     p_spu->i_stop = 0;
387     p_spu->b_ephemer = true;
388
389     /* Send an empty subpicture to clear the display when needed */
390     if (!p_pic || !p_BarGraph->i_alpha)
391         goto exit;
392
393     /* Create new SPU region */
394     memset(&fmt, 0, sizeof(video_format_t));
395     fmt.i_chroma = VLC_CODEC_YUVA;
396     fmt.i_sar_num = fmt.i_sar_den = 1;
397     fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
398     fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
399     fmt.i_x_offset = fmt.i_y_offset = 0;
400     p_region = subpicture_region_New(&fmt);
401     if (!p_region) {
402         msg_Err(p_filter, "cannot allocate SPU region");
403         subpicture_Delete(p_spu);
404         p_spu = NULL;
405         goto exit;
406     }
407
408     /* */
409     picture_Copy(p_region->p_picture, p_pic);
410
411     /*  where to locate the bar graph: */
412     if (p_sys->i_pos < 0) {   /*  set to an absolute xy */
413         p_region->i_align = SUBPICTURE_ALIGN_RIGHT | SUBPICTURE_ALIGN_TOP;
414         p_spu->b_absolute = true;
415     } else {   /* set to one of the 9 relative locations */
416         p_region->i_align = p_sys->i_pos;
417         p_spu->b_absolute = false;
418     }
419
420     p_region->i_x = p_sys->i_pos_x;
421     p_region->i_y = p_sys->i_pos_y;
422
423     p_spu->p_region = p_region;
424
425     p_spu->i_alpha = p_BarGraph->i_alpha ;
426
427 exit:
428     vlc_mutex_unlock(&p_sys->lock);
429
430     return p_spu;
431 }
432
433 /**
434  * Video filter
435  */
436 static picture_t *FilterVideo(filter_t *p_filter, picture_t *p_src)
437 {
438     filter_sys_t *p_sys = p_filter->p_sys;
439     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
440
441     picture_t *p_dst = filter_NewPicture(p_filter);
442     if (!p_dst) {
443         picture_Release(p_src);
444         return NULL;
445     }
446
447     picture_Copy(p_dst, p_src);
448
449     /* */
450     vlc_mutex_lock(&p_sys->lock);
451
452     /* */
453     const picture_t *p_pic = p_BarGraph->p_pic;
454     if (!p_pic)
455         goto out;
456
457     const video_format_t *p_fmt = &p_pic->format;
458     const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
459     const int i_dst_h = p_filter->fmt_out.video.i_visible_height;
460
461     if (p_sys->i_pos) {
462         if (p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM)
463             p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
464         else if (!(p_sys->i_pos & SUBPICTURE_ALIGN_TOP))
465             p_sys->i_pos_y = (i_dst_h - p_fmt->i_visible_height) / 2;
466         else
467             p_sys->i_pos_y = 0;
468
469         if (p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT)
470             p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
471         else if (!(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT))
472             p_sys->i_pos_x = (i_dst_w - p_fmt->i_visible_width) / 2;
473         else
474             p_sys->i_pos_x = 0;
475     }
476
477     /* */
478     const int i_alpha = p_BarGraph->i_alpha;
479     if (filter_ConfigureBlend(p_sys->p_blend, i_dst_w, i_dst_h, p_fmt) ||
480             filter_Blend(p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
481                 p_pic, i_alpha))
482         msg_Err(p_filter, "failed to blend a picture");
483
484 out:
485     vlc_mutex_unlock(&p_sys->lock);
486
487     picture_Release(p_src);
488     return p_dst;
489 }
490
491 /**
492  * Common open function
493  */
494 static int OpenCommon(vlc_object_t *p_this, bool b_sub)
495 {
496     filter_t *p_filter = (filter_t *)p_this;
497     filter_sys_t *p_sys;
498
499     /* */
500     if (!b_sub && !es_format_IsSimilar(&p_filter->fmt_in, &p_filter->fmt_out)) {
501         msg_Err(p_filter, "Input and output format does not match");
502         return VLC_EGENERIC;
503     }
504
505
506     /* */
507     p_filter->p_sys = p_sys = malloc(sizeof(*p_sys));
508     if (!p_sys)
509         return VLC_ENOMEM;
510
511     /* */
512     p_sys->p_blend = NULL;
513     if (!b_sub) {
514         p_sys->p_blend = filter_NewBlend(VLC_OBJECT(p_filter),
515                                           &p_filter->fmt_in.video);
516         if (!p_sys->p_blend) {
517             free(p_sys);
518             return VLC_EGENERIC;
519         }
520     }
521
522     /* */
523     config_ChainParse(p_filter, CFG_PREFIX, ppsz_filter_options,
524                        p_filter->p_cfg);
525
526     /* create and initialize variables */
527     p_sys->i_pos = var_CreateGetInteger(p_filter, CFG_PREFIX "position");
528     p_sys->i_pos_x = var_CreateGetInteger(p_filter, CFG_PREFIX "x");
529     p_sys->i_pos_y = var_CreateGetInteger(p_filter, CFG_PREFIX "y");
530     BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
531     p_BarGraph->p_pic = NULL;
532     p_BarGraph->i_alpha = var_CreateGetInteger(p_filter, CFG_PREFIX "transparency");
533     p_BarGraph->i_alpha = VLC_CLIP(p_BarGraph->i_alpha, 0, 255);
534     p_BarGraph->i_values = NULL;
535     parse_i_values(p_BarGraph, &(char){ 0 });
536     p_BarGraph->alarm = false;
537
538     p_BarGraph->barWidth = var_CreateGetInteger(p_filter, CFG_PREFIX "barWidth");
539     p_BarGraph->scale = 400;
540
541     /* Ignore aligment if a position is given for video filter */
542     if (!b_sub && p_sys->i_pos_x >= 0 && p_sys->i_pos_y >= 0)
543         p_sys->i_pos = 0;
544
545     vlc_mutex_init(&p_sys->lock);
546
547     var_Create(p_filter->p_libvlc, CFG_PREFIX "alarm", VLC_VAR_BOOL);
548     var_Create(p_filter->p_libvlc, CFG_PREFIX "i_values", VLC_VAR_STRING);
549
550     var_AddCallback(p_filter->p_libvlc, CFG_PREFIX "alarm",
551                     BarGraphCallback, p_sys);
552     var_AddCallback(p_filter->p_libvlc, CFG_PREFIX "i_values",
553                     BarGraphCallback, p_sys);
554
555     var_TriggerCallback(p_filter->p_libvlc, CFG_PREFIX "alarm");
556     var_TriggerCallback(p_filter->p_libvlc, CFG_PREFIX "i_values");
557
558     for (int i = 0; ppsz_filter_callbacks[i]; i++)
559         var_AddCallback(p_filter, ppsz_filter_callbacks[i],
560                          BarGraphCallback, p_sys);
561
562     if (b_sub)
563         p_filter->pf_sub_source = FilterSub;
564     else
565         p_filter->pf_video_filter = FilterVideo;
566
567     return VLC_SUCCESS;
568 }
569
570 /**
571  * Open the sub source
572  */
573 static int OpenSub(vlc_object_t *p_this)
574 {
575     return OpenCommon(p_this, true);
576 }
577
578 /**
579  * Open the video filter
580  */
581 static int OpenVideo(vlc_object_t *p_this)
582 {
583     return OpenCommon(p_this, false);
584 }
585
586 /**
587  * Common close function
588  */
589 static void Close(vlc_object_t *p_this)
590 {
591     filter_t *p_filter = (filter_t *)p_this;
592     filter_sys_t *p_sys = p_filter->p_sys;
593
594     for (int i = 0; ppsz_filter_callbacks[i]; i++)
595         var_DelCallback(p_filter, ppsz_filter_callbacks[i],
596                          BarGraphCallback, p_sys);
597
598     var_DelCallback(p_filter->p_libvlc, CFG_PREFIX "i_values",
599                     BarGraphCallback, p_sys);
600     var_DelCallback(p_filter->p_libvlc, CFG_PREFIX "alarm",
601                     BarGraphCallback, p_sys);
602     var_Destroy(p_filter->p_libvlc, CFG_PREFIX "i_values");
603     var_Destroy(p_filter->p_libvlc, CFG_PREFIX "alarm");
604
605     if (p_sys->p_blend)
606         filter_DeleteBlend(p_sys->p_blend);
607
608     vlc_mutex_destroy(&p_sys->lock);
609
610     if (p_sys->p_BarGraph.p_pic)
611         picture_Release(p_sys->p_BarGraph.p_pic);
612
613     free(p_sys->p_BarGraph.i_values);
614
615     free(p_sys);
616 }