audiobargraph_v.c 19.7 KB
Newer Older
1 2 3
/*****************************************************************************
 * audiobargraph_v.c : audiobargraph video plugin for vlc
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2003-2006 VLC authors and VideoLAN
5 6 7 8
 *
 * Authors: Clement CHESNIN <clement.chesnin@gmail.com>
 *          Philippe COENT <philippe.coent@tdf.fr>
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9 10 11
 * 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
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20 21
 * 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.
22 23 24 25 26 27 28 29 30 31
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
32
#include <math.h>
33 34 35 36 37 38 39 40 41 42

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_filter.h>

#include <vlc_image.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
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 49
#define TRANS_TEXT N_("Transparency of the bargraph")
#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 54 55
  "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).")
56 57 58 59
#define BARWIDTH_TEXT N_("Bar width in pixel")
#define BARWIDTH_LONGTEXT N_("Width in pixel of each bar in the BarGraph to be displayed." )
#define BARHEIGHT_TEXT N_("Bar Height in pixel")
#define BARHEIGHT_LONGTEXT N_("Height in pixel of BarGraph to be displayed." )
60 61 62 63 64 65 66 67

#define CFG_PREFIX "audiobargraph_v-"

static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
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") };

68 69 70
static int  OpenSub  (vlc_object_t *);
static int  OpenVideo(vlc_object_t *);
static void Close    (vlc_object_t *);
71 72 73

vlc_module_begin ()

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    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)
92
    add_integer(CFG_PREFIX "barHeight", 400, BARHEIGHT_TEXT, BARHEIGHT_LONGTEXT, true)
93 94 95

    /* video output filter submodule */
    add_submodule ()
96
    set_capability("video filter", 0)
97 98 99
    set_callbacks(OpenVideo, Close)
    set_description(N_("Audio Bar Graph Video sub source"))
    add_shortcut("audiobargraph_v")
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
vlc_module_end ()


/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

/*****************************************************************************
 * Structure to hold the Bar Graph properties
 ****************************************************************************/
typedef struct
{
    int i_alpha;       /* -1 means use default alpha */
    int nbChannels;
    int *i_values;
    picture_t *p_pic;
    mtime_t date;
    int scale;
118
    bool alarm;
119 120 121 122 123 124 125 126 127 128 129 130
    int barWidth;

} BarGraph_t;

/**
 * Private data holder
 */
struct filter_sys_t
{
    filter_t *p_blend;

    vlc_mutex_t lock;
131

132 133 134 135 136 137 138 139 140 141 142 143
    BarGraph_t p_BarGraph;

    int i_pos;
    int i_pos_x;
    int i_pos_y;
    bool b_absolute;

    /* On the fly control variable */
    bool b_spu_update;
};

static const char *const ppsz_filter_options[] = {
144
    "x", "y", "transparency", "position", "barWidth", "barHeight", NULL
145 146 147 148 149 150 151 152
};

static const char *const ppsz_filter_callbacks[] = {
    "audiobargraph_v-x",
    "audiobargraph_v-y",
    "audiobargraph_v-transparency",
    "audiobargraph_v-position",
    "audiobargraph_v-barWidth",
153
    "audiobargraph_v-barHeight",
154 155 156 157
    NULL
};

/*****************************************************************************
158
 * IEC 268-18  Source: meterbridge
159
 *****************************************************************************/
160
static float iec_scale(float dB)
161
{
162 163 164 165 166 167
    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;
168
    if (dB < -40.0f)
169 170 171 172 173 174 175 176
        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;
177 178 179 180 181
}

/*****************************************************************************
 * parse_i_values : parse i_values parameter and store the corresponding values
 *****************************************************************************/
182
static void parse_i_values(BarGraph_t *p_BarGraph, char *i_values)
183 184 185 186 187
{
    char delim[] = ":";
    char* tok;

    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 192 193 194
    while (res != NULL) {
        p_BarGraph->nbChannels++;
        p_BarGraph->i_values = xrealloc(p_BarGraph->i_values,
                                          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 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
/* Drawing */

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)
{
    for (int j = 0; j < 4; j++)
        memset(&p[j].p_pixels[line * p[j].i_pitch + col], color[j], w);
}

static void Draw2VLines(plane_t *p, int scale, int col, const uint8_t color[4])
{
    for (int i = 10; i < scale + 10; i++)
        DrawHLine(p, i, col, color, 2);
}

static void DrawHLines(plane_t *p, int line, int col, const uint8_t color[4], int h, int w)
{
    for (int i = line; i < line + h; i++)
        DrawHLine(p, i, col, color, w);
}

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);
        }
    }
}
241
/*****************************************************************************
242
 * Draw: creates and returns the bar graph image
243
 *****************************************************************************/
244
static void Draw(BarGraph_t *b)
245
{
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    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)
263
        return;
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
    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]);
286
    }
287

288 289 290 291
    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;
292

293 294
    for (int i = 0; i < nbChannels; i++) {
        int pi = 30 + i * (5 + barWidth);
295

296
        DrawHLines(p, h - 20 - 1, pi, indicator_color, 8, barWidth);
297

298 299 300 301 302 303 304
        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);
305
        }
306

307 308 309 310 311 312 313
        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);
314 315 316 317 318 319 320
        }
    }
}

/*****************************************************************************
 * Callback to update params on the fly
 *****************************************************************************/
321 322
static int BarGraphCallback(vlc_object_t *p_this, char const *psz_var,
                         vlc_value_t oldval, vlc_value_t newval, void *p_data)
323
{
324
    VLC_UNUSED(p_this); VLC_UNUSED(oldval);
325 326
    filter_sys_t *p_sys = p_data;
    BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
327

328
    vlc_mutex_lock(&p_sys->lock);
329
    if (!strcmp(psz_var, CFG_PREFIX "x"))
330
        p_sys->i_pos_x = newval.i_int;
331
    else if (!strcmp(psz_var, CFG_PREFIX "y"))
332
        p_sys->i_pos_y = newval.i_int;
333
    else if (!strcmp(psz_var, CFG_PREFIX "position"))
334
        p_sys->i_pos = newval.i_int;
335
    else if (!strcmp(psz_var, CFG_PREFIX "transparency"))
336
        p_BarGraph->i_alpha = VLC_CLIP(newval.i_int, 0, 255);
337
    else if (!strcmp(psz_var, CFG_PREFIX "i_values")) {
338 339
        if (newval.psz_string)
            parse_i_values(p_BarGraph, newval.psz_string);
340
        Draw(p_BarGraph);
341
    } else if (!strcmp(psz_var, CFG_PREFIX "alarm")) {
342
        p_BarGraph->alarm = newval.b_bool;
343
        Draw(p_BarGraph);
344
    } else if (!strcmp(psz_var, CFG_PREFIX "barWidth")) {
345
        p_BarGraph->barWidth = newval.i_int;
346
        Draw(p_BarGraph);
347 348 349
    } else if (!strcmp(psz_var, CFG_PREFIX "barHeight")) {
        p_BarGraph->scale = newval.i_int;
        Draw(p_BarGraph);
350 351
    }
    p_sys->b_spu_update = true;
352
    vlc_mutex_unlock(&p_sys->lock);
353 354 355 356 357 358 359

    return VLC_SUCCESS;
}

/**
 * Sub source
 */
360
static subpicture_t *FilterSub(filter_t *p_filter, mtime_t date)
361 362 363 364 365 366 367 368 369
{
    filter_sys_t *p_sys = p_filter->p_sys;
    BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);

    subpicture_t *p_spu;
    subpicture_region_t *p_region;
    video_format_t fmt;
    picture_t *p_pic;

370
    vlc_mutex_lock(&p_sys->lock);
371
    /* Basic test:  b_spu_update occurs on a dynamic change */
372 373
    if (!p_sys->b_spu_update) {
        vlc_mutex_unlock(&p_sys->lock);
374
        return NULL;
375 376 377 378 379
    }

    p_pic = p_BarGraph->p_pic;

    /* Allocate the subpicture internal data. */
380 381
    p_spu = filter_NewSubpicture(p_filter);
    if (!p_spu)
382 383 384 385 386 387 388 389
        goto exit;

    p_spu->b_absolute = p_sys->b_absolute;
    p_spu->i_start = date;
    p_spu->i_stop = 0;
    p_spu->b_ephemer = true;

    /* Send an empty subpicture to clear the display when needed */
390
    if (!p_pic || !p_BarGraph->i_alpha)
391 392 393
        goto exit;

    /* Create new SPU region */
394
    memset(&fmt, 0, sizeof(video_format_t));
395 396 397 398 399
    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;
400 401 402
    p_region = subpicture_region_New(&fmt);
    if (!p_region) {
        msg_Err(p_filter, "cannot allocate SPU region");
403
        subpicture_Delete(p_spu);
404 405 406 407 408
        p_spu = NULL;
        goto exit;
    }

    /* */
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 414
        p_region->i_align = SUBPICTURE_ALIGN_RIGHT | SUBPICTURE_ALIGN_TOP;
        p_spu->b_absolute = true;
415
    } else {   /* set to one of the 9 relative locations */
416 417 418 419 420 421 422 423 424 425 426 427
        p_region->i_align = p_sys->i_pos;
        p_spu->b_absolute = false;
    }

    p_region->i_x = p_sys->i_pos_x;
    p_region->i_y = p_sys->i_pos_y;

    p_spu->p_region = p_region;

    p_spu->i_alpha = p_BarGraph->i_alpha ;

exit:
428
    vlc_mutex_unlock(&p_sys->lock);
429 430 431 432 433 434 435

    return p_spu;
}

/**
 * Video filter
 */
436
static picture_t *FilterVideo(filter_t *p_filter, picture_t *p_src)
437 438 439 440
{
    filter_sys_t *p_sys = p_filter->p_sys;
    BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);

441 442 443 444 445
    picture_t *p_dst = filter_NewPicture(p_filter);
    if (!p_dst) {
        picture_Release(p_src);
        return NULL;
    }
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 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    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;
    }
476

477 478 479 480 481 482
    /* */
    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");
483

484 485
out:
    vlc_mutex_unlock(&p_sys->lock);
486

487
    picture_Release(p_src);
488
    return p_dst;
489 490
}

491 492 493
/**
 * Common open function
 */
494
static int OpenCommon(vlc_object_t *p_this, bool b_sub)
495
{
496 497
    filter_t *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys;
498

499
    /* */
500 501
    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");
502
        return VLC_EGENERIC;
503 504 505
    }


506
    /* */
507 508
    p_filter->p_sys = p_sys = malloc(sizeof(*p_sys));
    if (!p_sys)
509
        return VLC_ENOMEM;
510

511 512
    /* */
    p_sys->p_blend = NULL;
513 514 515 516 517
    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);
518 519 520 521 522
            return VLC_EGENERIC;
        }
    }

    /* */
523 524
    config_ChainParse(p_filter, CFG_PREFIX, ppsz_filter_options,
                       p_filter->p_cfg);
525 526

    /* create and initialize variables */
527 528 529
    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");
530 531
    BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
    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 536 537
    parse_i_values(p_BarGraph, &(char){ 0 });
    p_BarGraph->alarm = false;

538
    p_BarGraph->barWidth = var_CreateGetInteger(p_filter, CFG_PREFIX "barWidth");
539
    p_BarGraph->scale = var_CreateGetInteger( p_filter, CFG_PREFIX "barHeight");
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 544
        p_sys->i_pos = 0;

545
    vlc_mutex_init(&p_sys->lock);
546 547
    var_Create(p_filter->obj.libvlc, CFG_PREFIX "alarm", VLC_VAR_BOOL);
    var_Create(p_filter->obj.libvlc, CFG_PREFIX "i_values", VLC_VAR_STRING);
548

549
    var_AddCallback(p_filter->obj.libvlc, CFG_PREFIX "alarm",
550
                    BarGraphCallback, p_sys);
551
    var_AddCallback(p_filter->obj.libvlc, CFG_PREFIX "i_values",
552 553
                    BarGraphCallback, p_sys);

554 555
    var_TriggerCallback(p_filter->obj.libvlc, CFG_PREFIX "alarm");
    var_TriggerCallback(p_filter->obj.libvlc, CFG_PREFIX "i_values");
556

557 558 559
    for (int i = 0; ppsz_filter_callbacks[i]; i++)
        var_AddCallback(p_filter, ppsz_filter_callbacks[i],
                         BarGraphCallback, p_sys);
560

561
    if (b_sub)
562 563 564
        p_filter->pf_sub_source = FilterSub;
    else
        p_filter->pf_video_filter = FilterVideo;
565

566
    return VLC_SUCCESS;
567
}
568

569 570 571
/**
 * Open the sub source
 */
572
static int OpenSub(vlc_object_t *p_this)
573
{
574
    return OpenCommon(p_this, true);
575
}
576

577 578 579
/**
 * Open the video filter
 */
580
static int OpenVideo(vlc_object_t *p_this)
581
{
582
    return OpenCommon(p_this, false);
583
}
584

585 586 587
/**
 * Common close function
 */
588
static void Close(vlc_object_t *p_this)
589 590 591 592
{
    filter_t *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys = p_filter->p_sys;

593 594 595
    for (int i = 0; ppsz_filter_callbacks[i]; i++)
        var_DelCallback(p_filter, ppsz_filter_callbacks[i],
                         BarGraphCallback, p_sys);
596

597
    var_DelCallback(p_filter->obj.libvlc, CFG_PREFIX "i_values",
598
                    BarGraphCallback, p_sys);
599
    var_DelCallback(p_filter->obj.libvlc, CFG_PREFIX "alarm",
600
                    BarGraphCallback, p_sys);
601 602
    var_Destroy(p_filter->obj.libvlc, CFG_PREFIX "i_values");
    var_Destroy(p_filter->obj.libvlc, CFG_PREFIX "alarm");
603

604 605
    if (p_sys->p_blend)
        filter_DeleteBlend(p_sys->p_blend);
606

607
    vlc_mutex_destroy(&p_sys->lock);
608

609 610
    if (p_sys->p_BarGraph.p_pic)
        picture_Release(p_sys->p_BarGraph.p_pic);
611

612
    free(p_sys->p_BarGraph.i_values);
613

614
    free(p_sys);
615
}