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