]> git.sesse.net Git - vlc/blobdiff - modules/video_filter/audiobargraph_v.c
postproc: reduce lock contention in callback
[vlc] / modules / video_filter / audiobargraph_v.c
index 69a8f50688eb216d37a6366d6fd855e09e99ad13..f779033156e7891c257de78e0837316071b2eeab 100644 (file)
@@ -1,24 +1,24 @@
 /*****************************************************************************
  * audiobargraph_v.c : audiobargraph video plugin for vlc
  *****************************************************************************
- * Copyright (C) 2003-2006 the VideoLAN team
+ * Copyright (C) 2003-2006 VLC authors and VideoLAN
  *
  * Authors: Clement CHESNIN <clement.chesnin@gmail.com>
  *          Philippe COENT <philippe.coent@tdf.fr>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -29,6 +29,7 @@
 # include "config.h"
 #endif
 #include <string.h>
+#include <math.h>
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 
 #include <vlc_image.h>
 
-#ifdef LoadImage
-#   undef LoadImage
-#endif
-
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-#define I_VALUES_TEXT N_("Value of the audio channels levels")
-#define I_VALUES_LONGTEXT N_("Value of the audio level of each channels between 0 and 1" \
-    "Each level should be separated with ':'.")
+
 #define POSX_TEXT N_("X coordinate")
-#define POSX_LONGTEXT N_("X coordinate of the bargraph." )
+#define POSX_LONGTEXT N_("X coordinate of the bargraph.")
 #define POSY_TEXT N_("Y coordinate")
-#define POSY_LONGTEXT N_("Y coordinate of the bargraph." )
+#define POSY_LONGTEXT N_("Y coordinate of the bargraph.")
 #define TRANS_TEXT N_("Transparency of the bargraph")
 #define TRANS_LONGTEXT N_("Bargraph transparency value " \
-  "(from 0 for full transparency to 255 for full opacity)." )
+  "(from 0 for full transparency to 255 for full opacity).")
 #define POS_TEXT N_("Bargraph position")
-#define POS_LONGTEXT N_( \
+#define POS_LONGTEXT N_(\
   "Enforce the bargraph position on the video " \
   "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
   "also use combinations of these values, eg 6 = top-right).")
-#define ALARM_TEXT N_("Alarm")
-#define ALARM_LONGTEXT N_("Signals a silence and displays and alert " \
-                "(0=no alarm, 1=alarm).")
 #define BARWIDTH_TEXT N_("Bar width in pixel (default : 10)")
 #define BARWIDTH_LONGTEXT N_("Width in pixel of each bar in the BarGraph to be displayed " \
                 "(default : 10).")
@@ -73,37 +64,37 @@ static const char *const ppsz_pos_descriptions[] =
 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
   N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
 
-static int  OpenSub  ( vlc_object_t * );
-static int  OpenVideo( vlc_object_t * );
-static void Close    ( vlc_object_t * );
+static int  OpenSub  (vlc_object_t *);
+static int  OpenVideo(vlc_object_t *);
+static void Close    (vlc_object_t *);
 
 vlc_module_begin ()
 
-    set_category( CAT_VIDEO )
-    set_subcategory( SUBCAT_VIDEO_SUBPIC )
-
-    set_capability( "sub source", 0 )
-    set_callbacks( OpenSub, Close )
-    set_description( N_("Audio Bar Graph Video sub source") )
-    set_shortname( N_("Audio Bar Graph Video") )
-    add_shortcut( "audiobargraph_v" )
-
-    add_string( CFG_PREFIX "i_values", NULL, I_VALUES_TEXT, I_VALUES_LONGTEXT, false )
-    add_integer( CFG_PREFIX "x", 0, POSX_TEXT, POSX_LONGTEXT, true )
-    add_integer( CFG_PREFIX "y", 0, POSY_TEXT, POSY_LONGTEXT, true )
-    add_integer_with_range( CFG_PREFIX "transparency", 255, 0, 255, NULL,
-        TRANS_TEXT, TRANS_LONGTEXT, false )
-    add_integer( CFG_PREFIX "position", -1, POS_TEXT, POS_LONGTEXT, false )
-        change_integer_list( pi_pos_values, ppsz_pos_descriptions )
-    add_integer( CFG_PREFIX "alarm", 0, ALARM_TEXT, ALARM_LONGTEXT, true )
-    add_integer( CFG_PREFIX "barWidth", 10, BARWIDTH_TEXT, BARWIDTH_LONGTEXT, true )
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_SUBPIC)
+
+    set_capability("sub source", 0)
+    set_callbacks(OpenSub, Close)
+    set_description(N_("Audio Bar Graph Video sub source"))
+    set_shortname(N_("Audio Bar Graph Video"))
+    add_shortcut("audiobargraph_v")
+
+    add_obsolete_string(CFG_PREFIX "i_values")
+    add_integer(CFG_PREFIX "x", 0, POSX_TEXT, POSX_LONGTEXT, true)
+    add_integer(CFG_PREFIX "y", 0, POSY_TEXT, POSY_LONGTEXT, true)
+    add_integer_with_range(CFG_PREFIX "transparency", 255, 0, 255,
+        TRANS_TEXT, TRANS_LONGTEXT, false)
+    add_integer(CFG_PREFIX "position", -1, POS_TEXT, POS_LONGTEXT, false)
+        change_integer_list(pi_pos_values, ppsz_pos_descriptions)
+    add_obsolete_integer(CFG_PREFIX "alarm")
+    add_integer(CFG_PREFIX "barWidth", 10, BARWIDTH_TEXT, BARWIDTH_LONGTEXT, true)
 
     /* video output filter submodule */
     add_submodule ()
-    set_capability( "video filter2", 0 )
-    set_callbacks( OpenVideo, Close )
-    set_description( N_("Audio Bar Graph Video sub source") )
-    add_shortcut( "audiobargraph_v" )
+    set_capability("video filter2", 0)
+    set_callbacks(OpenVideo, Close)
+    set_description(N_("Audio Bar Graph Video sub source"))
+    add_shortcut("audiobargraph_v")
 vlc_module_end ()
 
 
@@ -122,7 +113,7 @@ typedef struct
     picture_t *p_pic;
     mtime_t date;
     int scale;
-    int alarm;
+    bool alarm;
     int barWidth;
 
 } BarGraph_t;
@@ -135,7 +126,7 @@ struct filter_sys_t
     filter_t *p_blend;
 
     vlc_mutex_t lock;
-    
+
     BarGraph_t p_BarGraph;
 
     int i_pos;
@@ -148,163 +139,225 @@ struct filter_sys_t
 };
 
 static const char *const ppsz_filter_options[] = {
-    "i_values", "x", "y", "transparency", "position", "alarm", "barWidth", NULL
+    "x", "y", "transparency", "position", "barWidth", NULL
 };
 
 static const char *const ppsz_filter_callbacks[] = {
-    "audiobargraph_v-i_values",
     "audiobargraph_v-x",
     "audiobargraph_v-y",
     "audiobargraph_v-transparency",
     "audiobargraph_v-position",
-    "audiobargraph_v-alarm",
     "audiobargraph_v-barWidth",
     NULL
 };
 
-static int OpenCommon( vlc_object_t *, bool b_sub );
+/*****************************************************************************
+ * IEC 268-18  Source: meterbridge
+ *****************************************************************************/
+static float iec_scale(float dB)
+{
+    if (dB < -70.0f)
+        return 0.0f;
+    if (dB < -60.0f)
+        return (dB + 70.0f) * 0.0025f;
+    if (dB < -50.0f)
+        return (dB + 60.0f) * 0.005f + 0.025f;
+    if (dB < -40.0)
+        return (dB + 50.0f) * 0.0075f + 0.075f;
+    if (dB < -30.0f)
+        return (dB + 40.0f) * 0.015f + 0.15f;
+    if (dB < -20.0f)
+        return (dB + 30.0f) * 0.02f + 0.3f;
+    if (dB < -0.001f || dB > 0.001f)  /* if (dB < 0.0f) */
+        return (dB + 20.0f) * 0.025f + 0.5f;
+    return 1.0f;
+}
 
-static subpicture_t *FilterSub( filter_t *, mtime_t );
-static picture_t    *FilterVideo( filter_t *, picture_t * );
+/*****************************************************************************
+ * parse_i_values : parse i_values parameter and store the corresponding values
+ *****************************************************************************/
+static void parse_i_values(BarGraph_t *p_BarGraph, char *i_values)
+{
+    char delim[] = ":";
+    char* tok;
 
-static int BarGraphCallback( vlc_object_t *, char const *,
-                         vlc_value_t, vlc_value_t, void * );
+    p_BarGraph->nbChannels = 0;
+    free(p_BarGraph->i_values);
+    p_BarGraph->i_values = NULL;
+    char *res = strtok_r(i_values, delim, &tok);
+    while (res != NULL) {
+        p_BarGraph->nbChannels++;
+        p_BarGraph->i_values = xrealloc(p_BarGraph->i_values,
+                                          p_BarGraph->nbChannels*sizeof(int));
+        float db = log10(atof(res)) * 20;
+        p_BarGraph->i_values[p_BarGraph->nbChannels-1] = VLC_CLIP(iec_scale(db)*p_BarGraph->scale, 0, p_BarGraph->scale);
+        res = strtok_r(NULL, delim, &tok);
+    }
+}
 
-static void LoadBarGraph( vlc_object_t *, BarGraph_t *);
-void parse_i_values( BarGraph_t *p_BarGraph, char *i_values);
+/* Drawing */
 
-/**
- * Open the sub source
- */
-static int OpenSub( vlc_object_t *p_this )
+static const uint8_t bright_red[4]   = { 76, 85, 0xff, 0xff };
+static const uint8_t black[4] = { 0x00, 0x80, 0x80, 0xff };
+static const uint8_t white[4] = { 0xff, 0x80, 0x80, 0xff };
+static const uint8_t bright_green[4] = { 150, 44, 21, 0xff };
+static const uint8_t bright_yellow[4] = { 226, 1, 148, 0xff };
+static const uint8_t green[4] = { 74, 85, 74, 0xff };
+static const uint8_t yellow[4] = { 112, 64, 138, 0xff };
+static const uint8_t red[4] = { 37, 106, 191, 0xff };
+
+static inline void DrawHLine(plane_t *p, int line, int col, const uint8_t color[4], int w)
 {
-    return OpenCommon( p_this, true );
+    for (int j = 0; j < 4; j++)
+        memset(&p[j].p_pixels[line * p[j].i_pitch + col], color[j], w);
 }
 
-/**
- * Open the video filter
- */
-static int OpenVideo( vlc_object_t *p_this )
+static void Draw2VLines(plane_t *p, int scale, int col, const uint8_t color[4])
 {
-    return OpenCommon( p_this, false );
+    for (int i = 10; i < scale + 10; i++)
+        DrawHLine(p, i, col, color, 2);
 }
 
-/**
- * Common open function
- */
-static int OpenCommon( vlc_object_t *p_this, bool b_sub )
+static void DrawHLines(plane_t *p, int line, int col, const uint8_t color[4], int h, int w)
 {
-    filter_t *p_filter = (filter_t *)p_this;
-    filter_sys_t *p_sys;
-    BarGraph_t *p_BarGraph;
-    char* i_values = NULL;
-
-    /* */
-    if( !b_sub && !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) )
-    {
-        msg_Err( p_filter, "Input and output format does not match" );
-        return VLC_EGENERIC;
-    }
-
-
-    /* */
-    p_filter->p_sys = p_sys = malloc( sizeof( *p_sys ) );
-    if( !p_sys )
-        return VLC_ENOMEM;
-    p_BarGraph = &(p_sys->p_BarGraph);
+    for (int i = line; i < line + h; i++)
+        DrawHLine(p, i, col, color, w);
+}
 
-    /* */
-    p_sys->p_blend = NULL;
-    if( !b_sub )
-    {
-
-        p_sys->p_blend = filter_NewBlend( VLC_OBJECT(p_filter),
-                                          &p_filter->fmt_in.video );
-        if( !p_sys->p_blend )
-        {
-            //free( p_BarGraph );
-            free( p_sys );
-            return VLC_EGENERIC;
+static void DrawNumber(plane_t *p, int h, const uint8_t data[5], int l)
+{
+    for (int i = 0; i < 5; i++) {
+        uint8_t x = data[i];
+        for (int j = 0; j < 7; j++) {
+            x <<= 1;
+            if (x & 0x80)
+                DrawHLine(p, h - l + 2 - 1 - i, 12 + j, black, 1);
         }
     }
+}
+/*****************************************************************************
+ * Draw: creates and returns the bar graph image
+ *****************************************************************************/
+static void Draw(BarGraph_t *b)
+{
+    int nbChannels = b->nbChannels;
+    int scale      = b->scale;
+    int barWidth   = b->barWidth;
+
+    int w = 40;
+    if (nbChannels > 0)
+        w = 2 * nbChannels * barWidth + 30;
+    int h = scale + 30;
+
+    int level[6];
+    for (int i = 0; i < 6; i++)
+        level[i] = iec_scale(-(i+1) * 10) * scale + 20;
+
+    if (b->p_pic)
+        picture_Release(b->p_pic);
+    b->p_pic = picture_New(VLC_FOURCC('Y','U','V','A'), w, h, 1, 1);
+    if (!b->p_pic)
+        return;
+    picture_t *p_pic = b->p_pic;
+    plane_t *p = p_pic->p;
+
+    for (int i = 0 ; i < p_pic->i_planes ; i++)
+        memset(p[i].p_pixels, 0x00, p[i].i_visible_lines * p[i].i_pitch);
+
+    Draw2VLines(p, scale, 20, black);
+    Draw2VLines(p, scale, 22, white);
+
+    static const uint8_t pixmap[6][5] = {
+        { 0x17, 0x15, 0x15, 0x15, 0x17 },
+        { 0x77, 0x45, 0x75, 0x15, 0x77 },
+        { 0x77, 0x15, 0x75, 0x15, 0x77 },
+        { 0x17, 0x15, 0x75, 0x55, 0x57 },
+        { 0x77, 0x15, 0x75, 0x45, 0x77 },
+        { 0x77, 0x55, 0x75, 0x45, 0x77 },
+    };
+
+    for (int i = 0; i < 6; i++) {
+        DrawHLines(p, h - 1 - level[i] - 1, 24, white, 1, 3);
+        DrawHLines(p, h - 1 - level[i],     24, black, 2, 3);
+        DrawNumber(p, h, pixmap[i], level[i]);
+    }
 
-    /* */
-    config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
-                       p_filter->p_cfg );
+    int minus8  = iec_scale(- 8) * scale + 20;
+    int minus18 = iec_scale(-18) * scale + 20;
+    int *i_values  = b->i_values;
+    const uint8_t *indicator_color = b->alarm ? bright_red : black;
 
-    /* create and initialize variables */
-    p_sys->i_pos = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-position" );
-    p_sys->i_pos_x = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-x" );
-    p_sys->i_pos_y = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-y" );
-    p_BarGraph->i_alpha = var_CreateGetIntegerCommand( p_filter,
-                                                        "audiobargraph_v-transparency" );
-    p_BarGraph->i_alpha = __MAX( __MIN( p_BarGraph->i_alpha, 255 ), 0 );
-    i_values = var_CreateGetStringCommand( p_filter, "audiobargraph_v-i_values" );
-    //p_BarGraph->nbChannels = 0;
-    //p_BarGraph->i_values = NULL;
-    parse_i_values(p_BarGraph, i_values);
-    p_BarGraph->alarm = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-alarm" );
-    p_BarGraph->barWidth = var_CreateGetIntegerCommand( p_filter, "audiobargraph_v-barWidth" );
-    p_BarGraph->scale = 400;
+    for (int i = 0; i < nbChannels; i++) {
+        int pi = 30 + i * (5 + barWidth);
 
-    /* Ignore aligment if a position is given for video filter */
-    if( !b_sub && p_sys->i_pos_x >= 0 && p_sys->i_pos_y >= 0 )
-        p_sys->i_pos = 0;
+        DrawHLines(p, h - 20 - 1, pi, indicator_color, 8, barWidth);
 
-    vlc_mutex_init( &p_sys->lock );
-    LoadBarGraph( p_this, p_BarGraph );
-    p_sys->b_spu_update = true;
-
-    for( int i = 0; ppsz_filter_callbacks[i]; i++ )
-        var_AddCallback( p_filter, ppsz_filter_callbacks[i],
-                         BarGraphCallback, p_sys );
+        for (int line = 20; line < i_values[i] + 20; line++) {
+            if (line < minus18)
+                DrawHLines(p, h - line - 1, pi, bright_green, 1, barWidth);
+            else if (line < minus8)
+                DrawHLines(p, h - line - 1, pi, bright_yellow, 1, barWidth);
+            else
+                DrawHLines(p, h - line - 1, pi, bright_red, 1, barWidth);
+        }
 
-    /* Misc init */
-    if( b_sub )
-    {
-        p_filter->pf_sub_source = FilterSub;
-    }
-    else
-    {
-        p_filter->pf_video_filter = FilterVideo;
+        for (int line = i_values[i] + 20; line < scale + 20; line++) {
+            if (line < minus18)
+                DrawHLines(p, h - line - 1, pi, green, 1, barWidth);
+            else if (line < minus8)
+                DrawHLines(p, h - line - 1, pi, yellow, 1, barWidth);
+            else
+                DrawHLines(p, h - line - 1, pi, red, 1, barWidth);
+        }
     }
-
-    free( i_values );
-    return VLC_SUCCESS;
 }
 
-/**
- * Common close function
- */
-static void Close( vlc_object_t *p_this )
+/*****************************************************************************
+ * Callback to update params on the fly
+ *****************************************************************************/
+static int BarGraphCallback(vlc_object_t *p_this, char const *psz_var,
+                         vlc_value_t oldval, vlc_value_t newval, void *p_data)
 {
-    filter_t *p_filter = (filter_t *)p_this;
-    filter_sys_t *p_sys = p_filter->p_sys;
-    BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
-
-    for( int i = 0; ppsz_filter_callbacks[i]; i++ )
-        var_DelCallback( p_filter, ppsz_filter_callbacks[i],
-                         BarGraphCallback, p_sys );
-
-    if( p_sys->p_blend )
-        filter_DeleteBlend( p_sys->p_blend );
+    VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+    filter_sys_t *p_sys = p_data;
+    BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
+    char* res = NULL;
 
-    vlc_mutex_destroy( &p_sys->lock );
-    
-    if( p_BarGraph->p_pic )
-    {
-        picture_Release( p_BarGraph->p_pic );
-        p_BarGraph->p_pic = NULL;
+    vlc_mutex_lock(&p_sys->lock);
+    if (!strcmp(psz_var, CFG_PREFIX "x"))
+        p_sys->i_pos_x = newval.i_int;
+    else if (!strcmp(psz_var, CFG_PREFIX "y"))
+        p_sys->i_pos_y = newval.i_int;
+    else if (!strcmp(psz_var, CFG_PREFIX "position"))
+        p_sys->i_pos = newval.i_int;
+    else if (!strcmp(psz_var, CFG_PREFIX "transparency"))
+        p_BarGraph->i_alpha = VLC_CLIP(newval.i_int, 0, 255);
+    else if (!strcmp(psz_var, CFG_PREFIX "i_values")) {
+        char *psz = xstrdup(newval.psz_string ? newval.psz_string : "");
+        // in case many answer are received at the same time, only keep one
+        res = strchr(psz, '@');
+        if (res)
+            *res = '\0';
+        parse_i_values(p_BarGraph, psz);
+        free(psz);
+        Draw(p_BarGraph);
+    } else if (!strcmp(psz_var, CFG_PREFIX "alarm")) {
+        p_BarGraph->alarm = newval.b_bool;
+        Draw(p_BarGraph);
+    } else if (!strcmp(psz_var, CFG_PREFIX "barWidth")) {
+        p_BarGraph->barWidth = newval.i_int;
+        Draw(p_BarGraph);
     }
-    free( p_BarGraph->i_values );
-    
-    free( p_sys );
+    p_sys->b_spu_update = true;
+    vlc_mutex_unlock(&p_sys->lock);
+
+    return VLC_SUCCESS;
 }
 
 /**
  * Sub source
  */
-static subpicture_t *FilterSub( filter_t *p_filter, mtime_t date )
+static subpicture_t *FilterSub(filter_t *p_filter, mtime_t date)
 {
     filter_sys_t *p_sys = p_filter->p_sys;
     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
@@ -314,19 +367,18 @@ static subpicture_t *FilterSub( filter_t *p_filter, mtime_t date )
     video_format_t fmt;
     picture_t *p_pic;
 
-    vlc_mutex_lock( &p_sys->lock );
+    vlc_mutex_lock(&p_sys->lock);
     /* Basic test:  b_spu_update occurs on a dynamic change */
-    if( !p_sys->b_spu_update )
-    {
-        vlc_mutex_unlock( &p_sys->lock );
-        return 0;
+    if (!p_sys->b_spu_update) {
+        vlc_mutex_unlock(&p_sys->lock);
+        return NULL;
     }
 
     p_pic = p_BarGraph->p_pic;
 
     /* Allocate the subpicture internal data. */
-    p_spu = filter_NewSubpicture( p_filter );
-    if( !p_spu )
+    p_spu = filter_NewSubpicture(p_filter);
+    if (!p_spu)
         goto exit;
 
     p_spu->b_absolute = p_sys->b_absolute;
@@ -335,36 +387,32 @@ static subpicture_t *FilterSub( filter_t *p_filter, mtime_t date )
     p_spu->b_ephemer = true;
 
     /* Send an empty subpicture to clear the display when needed */
-    if( !p_pic || !p_BarGraph->i_alpha )
+    if (!p_pic || !p_BarGraph->i_alpha)
         goto exit;
 
     /* Create new SPU region */
-    memset( &fmt, 0, sizeof(video_format_t) );
+    memset(&fmt, 0, sizeof(video_format_t));
     fmt.i_chroma = VLC_CODEC_YUVA;
     fmt.i_sar_num = fmt.i_sar_den = 1;
     fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
     fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
     fmt.i_x_offset = fmt.i_y_offset = 0;
-    p_region = subpicture_region_New( &fmt );
-    if( !p_region )
-    {
-        msg_Err( p_filter, "cannot allocate SPU region" );
-        p_filter->pf_sub_buffer_del( p_filter, p_spu );
+    p_region = subpicture_region_New(&fmt);
+    if (!p_region) {
+        msg_Err(p_filter, "cannot allocate SPU region");
+        p_filter->pf_sub_buffer_del(p_filter, p_spu);
         p_spu = NULL;
         goto exit;
     }
 
     /* */
-    picture_Copy( p_region->p_picture, p_pic );
+    picture_Copy(p_region->p_picture, p_pic);
 
     /*  where to locate the bar graph: */
-    if( p_sys->i_pos < 0 )
-    {   /*  set to an absolute xy */
+    if (p_sys->i_pos < 0) {   /*  set to an absolute xy */
         p_region->i_align = SUBPICTURE_ALIGN_RIGHT | SUBPICTURE_ALIGN_TOP;
         p_spu->b_absolute = true;
-    }
-    else
-    {   /* set to one of the 9 relative locations */
+    } else {   /* set to one of the 9 relative locations */
         p_region->i_align = p_sys->i_pos;
         p_spu->b_absolute = false;
     }
@@ -377,7 +425,7 @@ static subpicture_t *FilterSub( filter_t *p_filter, mtime_t date )
     p_spu->i_alpha = p_BarGraph->i_alpha ;
 
 exit:
-    vlc_mutex_unlock( &p_sys->lock );
+    vlc_mutex_unlock(&p_sys->lock);
 
     return p_spu;
 }
@@ -385,562 +433,184 @@ exit:
 /**
  * Video filter
  */
-static picture_t *FilterVideo( filter_t *p_filter, picture_t *p_src )
+static picture_t *FilterVideo(filter_t *p_filter, picture_t *p_src)
 {
     filter_sys_t *p_sys = p_filter->p_sys;
     BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
 
-    picture_t *p_dst = filter_NewPicture( p_filter );
-    if( !p_dst )
-        goto exit;
+    picture_t *p_dst = filter_NewPicture(p_filter);
+    if (!p_dst) {
+        picture_Release(p_src);
+        return NULL;
+    }
 
-    picture_Copy( p_dst, p_src );
+    picture_Copy(p_dst, p_src);
 
     /* */
-    vlc_mutex_lock( &p_sys->lock );
+    vlc_mutex_lock(&p_sys->lock);
 
     /* */
     const picture_t *p_pic = p_BarGraph->p_pic;
-    if( p_pic )
-    {
-        const video_format_t *p_fmt = &p_pic->format;
-        const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
-        const int i_dst_h = p_filter->fmt_out.video.i_visible_height;
-
-        if( p_sys->i_pos )
-        {
-            if( p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM )
-            {
-                p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
-            }
-            else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_TOP) )
-            {
-                p_sys->i_pos_y = ( i_dst_h - p_fmt->i_visible_height ) / 2;
-            }
-            else
-            {
-                p_sys->i_pos_y = 0;
-            }
-
-            if( p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT )
-            {
-                p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
-            }
-            else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT) )
-            {
-                p_sys->i_pos_x = ( i_dst_w - p_fmt->i_visible_width ) / 2;
-            }
-            else
-            {
-                p_sys->i_pos_x = 0;
-            }
-        }
-
-        /* */
-        const int i_alpha = p_BarGraph->i_alpha;
-        if( filter_ConfigureBlend( p_sys->p_blend, i_dst_w, i_dst_h, p_fmt ) ||
-            filter_Blend( p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
-                          p_pic, i_alpha ) )
-        {
-            msg_Err( p_filter, "failed to blend a picture" );
-        }
+    if (!p_pic)
+        goto out;
+
+    const video_format_t *p_fmt = &p_pic->format;
+    const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
+    const int i_dst_h = p_filter->fmt_out.video.i_visible_height;
+
+    if (p_sys->i_pos) {
+        if (p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM)
+            p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
+        else if (!(p_sys->i_pos & SUBPICTURE_ALIGN_TOP))
+            p_sys->i_pos_y = (i_dst_h - p_fmt->i_visible_height) / 2;
+        else
+            p_sys->i_pos_y = 0;
+
+        if (p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT)
+            p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
+        else if (!(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT))
+            p_sys->i_pos_x = (i_dst_w - p_fmt->i_visible_width) / 2;
+        else
+            p_sys->i_pos_x = 0;
     }
-    vlc_mutex_unlock( &p_sys->lock );
 
-exit:
-    picture_Release( p_src );
+    /* */
+    const int i_alpha = p_BarGraph->i_alpha;
+    if (filter_ConfigureBlend(p_sys->p_blend, i_dst_w, i_dst_h, p_fmt) ||
+            filter_Blend(p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
+                p_pic, i_alpha))
+        msg_Err(p_filter, "failed to blend a picture");
+
+out:
+    vlc_mutex_unlock(&p_sys->lock);
+
+    picture_Release(p_src);
     return p_dst;
 }
 
-/*****************************************************************************
- * Callback to update params on the fly
- *****************************************************************************/
-static int BarGraphCallback( vlc_object_t *p_this, char const *psz_var,
-                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
+/**
+ * Common open function
+ */
+static int OpenCommon(vlc_object_t *p_this, bool b_sub)
 {
-    VLC_UNUSED(oldval);
-    filter_sys_t *p_sys = (filter_sys_t *)p_data;
-    BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
-    char* i_values;
-    char* res = NULL;
+    filter_t *p_filter = (filter_t *)p_this;
+    filter_sys_t *p_sys;
 
-    vlc_mutex_lock( &p_sys->lock );
-    if ( !strcmp( psz_var, "audiobargraph_v-x" ) )
-    {
-        p_sys->i_pos_x = newval.i_int;
-    }
-    else if ( !strcmp( psz_var, "audiobargraph_v-y" ) )
-    {
-        p_sys->i_pos_y = newval.i_int;
-    }
-    else if ( !strcmp( psz_var, "audiobargraph_v-position" ) )
-    {
-        p_sys->i_pos = newval.i_int;
-    }
-    else if ( !strcmp( psz_var, "audiobargraph_v-transparency" ) )
-    {
-        p_BarGraph->i_alpha = __MAX( __MIN( newval.i_int, 255 ), 0 );
-    }
-    else if ( !strcmp( psz_var, "audiobargraph_v-i_values" ) )
-    {
-        if( p_BarGraph->p_pic )
-        {
-            picture_Release( p_BarGraph->p_pic );
-            p_BarGraph->p_pic = NULL;
-        }
-        i_values = strdup( newval.psz_string );
-        free(p_BarGraph->i_values);
-        //p_BarGraph->i_values = NULL;
-        //p_BarGraph->nbChannels = 0;
-        // in case many answer are received at the same time, only keep one
-        res = strchr(i_values, '@');
-        if (res)
-            *res = 0;
-        parse_i_values( p_BarGraph, i_values);
-        LoadBarGraph(p_this,p_BarGraph);
-    }
-    else if ( !strcmp( psz_var, "audiobargraph_v-alarm" ) )
-    {
-        if( p_BarGraph->p_pic )
-        {
-            picture_Release( p_BarGraph->p_pic );
-            p_BarGraph->p_pic = NULL;
-        }
-        p_BarGraph->alarm = newval.i_int;
-        LoadBarGraph(p_this,p_BarGraph);
+    /* */
+    if (!b_sub && !es_format_IsSimilar(&p_filter->fmt_in, &p_filter->fmt_out)) {
+        msg_Err(p_filter, "Input and output format does not match");
+        return VLC_EGENERIC;
     }
-    else if ( !strcmp( psz_var, "audiobargraph_v-barWidth" ) )
-    {
-        if( p_BarGraph->p_pic )
-        {
-            picture_Release( p_BarGraph->p_pic );
-            p_BarGraph->p_pic = NULL;
+
+
+    /* */
+    p_filter->p_sys = p_sys = malloc(sizeof(*p_sys));
+    if (!p_sys)
+        return VLC_ENOMEM;
+
+    /* */
+    p_sys->p_blend = NULL;
+    if (!b_sub) {
+        p_sys->p_blend = filter_NewBlend(VLC_OBJECT(p_filter),
+                                          &p_filter->fmt_in.video);
+        if (!p_sys->p_blend) {
+            free(p_sys);
+            return VLC_EGENERIC;
         }
-        p_BarGraph->barWidth = newval.i_int;
-        LoadBarGraph(p_this,p_BarGraph);
     }
-    p_sys->b_spu_update = true;
-    vlc_mutex_unlock( &p_sys->lock );
+
+    /* */
+    config_ChainParse(p_filter, CFG_PREFIX, ppsz_filter_options,
+                       p_filter->p_cfg);
+
+    /* create and initialize variables */
+    p_sys->i_pos = var_CreateGetInteger(p_filter, CFG_PREFIX "position");
+    p_sys->i_pos_x = var_CreateGetInteger(p_filter, CFG_PREFIX "x");
+    p_sys->i_pos_y = var_CreateGetInteger(p_filter, CFG_PREFIX "y");
+    BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
+    p_BarGraph->p_pic = NULL;
+    p_BarGraph->i_alpha = var_CreateGetInteger(p_filter, CFG_PREFIX "transparency");
+    p_BarGraph->i_alpha = VLC_CLIP(p_BarGraph->i_alpha, 0, 255);
+    p_BarGraph->i_values = NULL;
+    parse_i_values(p_BarGraph, &(char){ 0 });
+    p_BarGraph->alarm = false;
+
+    p_BarGraph->barWidth = var_CreateGetInteger(p_filter, CFG_PREFIX "barWidth");
+    p_BarGraph->scale = 400;
+
+    /* Ignore aligment if a position is given for video filter */
+    if (!b_sub && p_sys->i_pos_x >= 0 && p_sys->i_pos_y >= 0)
+        p_sys->i_pos = 0;
+
+    vlc_mutex_init(&p_sys->lock);
+
+    var_Create(p_filter->p_libvlc, CFG_PREFIX "alarm", VLC_VAR_BOOL);
+    var_Create(p_filter->p_libvlc, CFG_PREFIX "i_values", VLC_VAR_STRING);
+
+    var_AddCallback(p_filter->p_libvlc, CFG_PREFIX "alarm",
+                    BarGraphCallback, p_sys);
+    var_AddCallback(p_filter->p_libvlc, CFG_PREFIX "i_values",
+                    BarGraphCallback, p_sys);
+
+    var_TriggerCallback(p_filter->p_libvlc, CFG_PREFIX "alarm");
+    var_TriggerCallback(p_filter->p_libvlc, CFG_PREFIX "i_values");
+
+    for (int i = 0; ppsz_filter_callbacks[i]; i++)
+        var_AddCallback(p_filter, ppsz_filter_callbacks[i],
+                         BarGraphCallback, p_sys);
+
+    if (b_sub)
+        p_filter->pf_sub_source = FilterSub;
+    else
+        p_filter->pf_video_filter = FilterVideo;
 
     return VLC_SUCCESS;
 }
 
-/*****************************************************************************
- * LoadImage: creates and returns the bar graph image
- *****************************************************************************/
-static picture_t *LoadImage( vlc_object_t *p_this, int nbChannels, int* i_values, int scale, int alarm, int barWidth)
+/**
+ * Open the sub source
+ */
+static int OpenSub(vlc_object_t *p_this)
 {
-    VLC_UNUSED(p_this);
-    picture_t *p_pic;
-    int i,j;
-    int i_width = 0;
-    int i_line;
-    int moinsTrois, moinsCinq, moinsSept, moinsDix, moinsVingt;
-    
-    if (nbChannels == 0) {
-        i_width = 20;
-    } else {
-        i_width = 2 * nbChannels * barWidth + 10;
-    }
-    
-    moinsTrois = 0.71*scale + 20;
-    moinsCinq = 0.56*scale + 20;
-    moinsSept = 0.45*scale + 20;
-    moinsDix = 0.32*scale + 20;
-    moinsVingt = 0.1*scale + 20;
-    
-    p_pic = picture_New(VLC_FOURCC('Y','U','V','A'), i_width+20, scale+30, 1, 1);
-    
-    // blacken the whole picture
-    for( i = 0 ; i < p_pic->i_planes ; i++ )
-    {
-        memset( p_pic->p[i].p_pixels, 0x00,
-                p_pic->p[i].i_visible_lines * p_pic->p[i].i_pitch );
-    }
-    
-    // side bar
-    for ( i_line = 20; i_line < scale+20; i_line++ ) {
-    
-#define DrawPointsBlack(a,b) {\
-        for (i=a; i<b; i++) {\
-            *(p_pic->p[0].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[0].i_pitch + i ) = 0x00; \
-            *(p_pic->p[1].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[1].i_pitch + i ) = 128; \
-            *(p_pic->p[2].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[2].i_pitch + i ) = 128; \
-            *(p_pic->p[3].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[3].i_pitch + i ) = 0xFF; \
-        }\
-    }
-#define DrawPointsWhite(a,b) {\
-        for (i=a; i<b; i++) {\
-            *(p_pic->p[0].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[0].i_pitch + i ) = 0xFF;\
-            *(p_pic->p[1].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[1].i_pitch + i ) = 128;\
-            *(p_pic->p[2].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[2].i_pitch + i ) = 128;\
-            *(p_pic->p[3].p_pixels + (scale + 30 - i_line - 1) * p_pic->p[3].i_pitch + i ) = 0xFF; \
-        }\
-    }    
-        
-        // vertical line
-        DrawPointsBlack(20,22);
-        DrawPointsWhite(22,24);
-    
-        // -3dB
-        if (i_line == moinsTrois - 2) {
-            // 3
-            DrawPointsBlack(16,19);
-        }
-        if (i_line == moinsTrois - 1) {
-            // 3
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsWhite(24,27);
-        }
-        if (i_line == moinsTrois) {
-            // 3
-            DrawPointsBlack(16,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsTrois + 1) {
-            // 3
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsTrois + 2) {
-            // 3
-            DrawPointsBlack(16,19);
-        }
-        
-        // -5dB
-        if (i_line == moinsCinq - 2) {
-            // 5
-            DrawPointsBlack(16,19);
-        }
-        if (i_line == moinsCinq - 1) {
-            // 5
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsWhite(24,27);
-        }
-        if (i_line == moinsCinq) {
-            // 5
-            DrawPointsBlack(16,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsCinq + 1) {
-            // 5
-            DrawPointsBlack(16,17);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsCinq + 2) {
-            // 5
-            DrawPointsBlack(16,19);
-        }
-        
-        // -7dB
-        if (i_line == moinsSept - 2) {
-            // 7
-            DrawPointsBlack(18,19);
-        }
-        if (i_line == moinsSept - 1) {
-            // 7
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsWhite(24,27);
-        }
-        if (i_line == moinsSept) {
-            // 7
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsSept + 1) {
-            // 7
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsSept + 2) {
-            // 7
-            DrawPointsBlack(16,19);
-        }
-        
-        
-        // -10dB
-        if (i_line == moinsDix - 2) {
-            // 1
-            DrawPointsBlack(14,15);
-            // 0
-            DrawPointsBlack(16,19);
-        }
-        if (i_line == moinsDix - 1) {
-            // 1
-            DrawPointsBlack(14,15);
-            // 0
-            DrawPointsBlack(16,17);
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsWhite(24,27);
-        }
-        if (i_line == moinsDix) {
-            // 1
-            DrawPointsBlack(14,15);
-            // 0
-            DrawPointsBlack(16,17);
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsDix + 1) {
-            // 1
-            DrawPointsBlack(14,15);
-            // 0
-            DrawPointsBlack(16,17);
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsDix + 2) {
-            // 1
-            DrawPointsBlack(14,15);
-            // 0
-            DrawPointsBlack(16,19);
-        }
-        
-        // -20dB
-        if (i_line == moinsVingt - 2) {
-            // 2
-            DrawPointsBlack(12,15);
-            // 0
-            DrawPointsBlack(16,19);
-        }
-        if (i_line == moinsVingt - 1) {
-            // 2
-            DrawPointsBlack(12,13);
-            // 0
-            DrawPointsBlack(16,17);
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsWhite(24,27);
-        }
-        if (i_line == moinsVingt) {
-            // 2
-            DrawPointsBlack(12,15);
-            // 0
-            DrawPointsBlack(16,17);
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsVingt + 1) {
-            // 2
-            DrawPointsBlack(14,15);
-            // 0
-            DrawPointsBlack(16,17);
-            DrawPointsBlack(18,19);
-            // limit
-            DrawPointsBlack(24,27);
-        }
-        if (i_line == moinsVingt + 2) {
-            // 2
-            DrawPointsBlack(12,15);
-            // 0
-            DrawPointsBlack(16,19);
-        }
-        
-        
-    }
-    
-    // draw the bars and channel indicators
-    for (i=0; i<nbChannels; i++) {
-        for( j = barWidth+20 ; j < 2*barWidth+20; j++)
-        {
-            // channel indicators
-            for ( i_line = 12; i_line < 18; i_line++ ) {
-                // white
-                *(p_pic->p[0].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[0].i_pitch +
-                    ( (2*i*barWidth)+j ) ) = 255;
-                *(p_pic->p[1].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[1].i_pitch +
-                    ( (2*i*barWidth)+j ) ) = 128;
-                *(p_pic->p[2].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[2].i_pitch +
-                    ( (2*i*barWidth)+j ) ) = 128;
-                *(p_pic->p[3].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[3].i_pitch +
-                    ( (2*i*barWidth)+j )) = 0xFF;
-            }
-            // bars
-            for( i_line = 20; i_line < i_values[i]+20; i_line++ )
-            {
-                if (i_line < moinsDix) { // green if < -10 dB
-                    *(p_pic->p[0].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[0].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 150;
-                    *(p_pic->p[1].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[1].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 44;
-                    *(p_pic->p[2].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[2].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 21;
-                    *(p_pic->p[3].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[3].i_pitch +
-                        ( (2*i*barWidth)+j )) = 0xFF;
-                } else if (i_line < moinsTrois) { // yellow if > -10dB and < -3dB
-                    *(p_pic->p[0].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[0].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 226;
-                    *(p_pic->p[1].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[1].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 1;
-                    *(p_pic->p[2].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[2].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 148;
-                    *(p_pic->p[3].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[3].i_pitch +
-                        ( (2*i*barWidth)+j )) = 0xFF;
-                } else { // red if > -3 dB
-                    *(p_pic->p[0].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[0].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 76;
-                    *(p_pic->p[1].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[1].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 85;
-                    *(p_pic->p[2].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[2].i_pitch +
-                        ( (2*i*barWidth)+j ) ) = 0xFF;
-                    *(p_pic->p[3].p_pixels +
-                        (scale + 30 - i_line - 1) *
-                        p_pic->p[3].i_pitch +
-                        ( (2*i*barWidth)+j )) = 0xFF;
-                }
-            }
-        }
-    }
-    
-    
-    
-    if (alarm) {// draw the alarm square
-        // bottom
-        for ( i_line = 0; i_line < 10; i_line++ ) {
-            for (i=0; i<i_width+20; i++) {
-                *(p_pic->p[0].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[0].i_pitch + i ) = 76;
-                *(p_pic->p[1].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[1].i_pitch + i ) = 85;
-                *(p_pic->p[2].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[2].i_pitch + i ) = 0xFF;
-                *(p_pic->p[3].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[3].i_pitch + i ) = 0xFF;
-            }
-        }
-        // top
-        for ( i_line = scale+21; i_line < scale+30; i_line++ ) {
-            for (i=0; i<i_width+20; i++) {
-                *(p_pic->p[0].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[0].i_pitch + i ) = 76;
-                *(p_pic->p[1].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[1].i_pitch + i ) = 85;
-                *(p_pic->p[2].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[2].i_pitch + i ) = 0xFF;
-                *(p_pic->p[3].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[3].i_pitch + i ) = 0xFF;
-            }
-        }
-        // sides
-        for ( i_line = 9; i_line < scale+21; i_line++ ) {
-            for (i=0; i<10; i++) {
-                *(p_pic->p[0].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[0].i_pitch + i ) = 76;
-                *(p_pic->p[1].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[1].i_pitch + i ) = 85;
-                *(p_pic->p[2].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[2].i_pitch + i ) = 0xFF;
-                *(p_pic->p[3].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[3].i_pitch + i ) = 0xFF;
-            }
-            for (i=i_width+11; i<i_width+20; i++) {
-                *(p_pic->p[0].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[0].i_pitch + i ) = 76;
-                *(p_pic->p[1].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[1].i_pitch + i ) = 85;
-                *(p_pic->p[2].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[2].i_pitch + i ) = 0xFF;
-                *(p_pic->p[3].p_pixels +
-                    (scale + 30 - i_line - 1) *
-                    p_pic->p[3].i_pitch + i ) = 0xFF;
-            }
-        }
-    }
-    
+    return OpenCommon(p_this, true);
+}
 
-    return p_pic;
+/**
+ * Open the video filter
+ */
+static int OpenVideo(vlc_object_t *p_this)
+{
+    return OpenCommon(p_this, false);
 }
 
-/*****************************************************************************
- * LoadBarGraph: loads the BarGraph images into memory
- *****************************************************************************/
-static void LoadBarGraph( vlc_object_t *p_this, BarGraph_t *p_BarGraph )
+/**
+ * Common close function
+ */
+static void Close(vlc_object_t *p_this)
 {
+    filter_t *p_filter = (filter_t *)p_this;
+    filter_sys_t *p_sys = p_filter->p_sys;
 
-    p_BarGraph->p_pic = LoadImage( p_this, p_BarGraph->nbChannels, p_BarGraph->i_values, p_BarGraph->scale, p_BarGraph->alarm, p_BarGraph->barWidth);
-    if( !p_BarGraph->p_pic )
-    {
-        msg_Warn( p_this, "error while creating picture" );
-    }
+    for (int i = 0; ppsz_filter_callbacks[i]; i++)
+        var_DelCallback(p_filter, ppsz_filter_callbacks[i],
+                         BarGraphCallback, p_sys);
 
-}
+    var_DelCallback(p_filter->p_libvlc, CFG_PREFIX "i_values",
+                    BarGraphCallback, p_sys);
+    var_DelCallback(p_filter->p_libvlc, CFG_PREFIX "alarm",
+                    BarGraphCallback, p_sys);
+    var_Destroy(p_filter->p_libvlc, CFG_PREFIX "i_values");
+    var_Destroy(p_filter->p_libvlc, CFG_PREFIX "alarm");
 
-/*****************************************************************************
- * parse_i_values : parse i_values parameter and store the corresponding values
- *****************************************************************************/
-void parse_i_values( BarGraph_t *p_BarGraph, char *i_values)
-{
-    char* res = NULL;
-    char delim[] = ":";
-    char* tok;
+    if (p_sys->p_blend)
+        filter_DeleteBlend(p_sys->p_blend);
 
-    p_BarGraph->nbChannels = 0;
-    p_BarGraph->i_values = NULL;
-    res = strtok_r(i_values, delim, &tok);
-    while (res != NULL) {
-        p_BarGraph->nbChannels++;
-        p_BarGraph->i_values = xrealloc(p_BarGraph->i_values,
-                                          p_BarGraph->nbChannels*sizeof(int));
-        p_BarGraph->i_values[p_BarGraph->nbChannels-1] = __MAX( __MIN( atof(res)*p_BarGraph->scale, p_BarGraph->scale ), 0 );
-        res = strtok_r(NULL, delim, &tok);
-    }
+    vlc_mutex_destroy(&p_sys->lock);
+
+    if (p_sys->p_BarGraph.p_pic)
+        picture_Release(p_sys->p_BarGraph.p_pic);
+
+    free(p_sys->p_BarGraph.i_values);
 
+    free(p_sys);
 }