qt: playlist: use item title if available
[vlc.git] / modules / spu / audiobargraph_v.c
blob89c44637039219f1dac63961ddaf7af323de75e0
1 /*****************************************************************************
2 * audiobargraph_v.c : audiobargraph video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2003-2006 VLC authors and VideoLAN
6 * Authors: Clement CHESNIN <clement.chesnin@gmail.com>
7 * Philippe COENT <philippe.coent@tdf.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <string.h>
32 #include <math.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37 #include <vlc_subpicture.h>
38 #include <vlc_image.h>
40 /*****************************************************************************
41 * Module descriptor
42 *****************************************************************************/
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." )
61 #define CFG_PREFIX "audiobargraph_v-"
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") };
68 static int OpenSub (filter_t *);
69 static int OpenVideo(filter_t *);
70 static void Close (filter_t *);
72 vlc_module_begin ()
74 set_category(CAT_VIDEO)
75 set_subcategory(SUBCAT_VIDEO_SUBPIC)
77 set_callback_sub_source(OpenSub, 0)
78 set_description(N_("Audio Bar Graph Video sub source"))
79 set_shortname(N_("Audio Bar Graph Video"))
80 add_shortcut("audiobargraph_v")
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 add_integer(CFG_PREFIX "barHeight", 400, BARHEIGHT_TEXT, BARHEIGHT_LONGTEXT, true)
93 /* video output filter submodule */
94 add_submodule ()
95 set_callback_video_filter(OpenVideo)
96 set_description(N_("Audio Bar Graph Video sub source"))
97 add_shortcut("audiobargraph_v")
98 vlc_module_end ()
101 /*****************************************************************************
102 * Local prototypes
103 *****************************************************************************/
105 /*****************************************************************************
106 * Structure to hold the Bar Graph properties
107 ****************************************************************************/
108 typedef struct
110 int i_alpha; /* -1 means use default alpha */
111 int nbChannels;
112 int *i_values;
113 picture_t *p_pic;
114 vlc_tick_t date;
115 int scale;
116 bool alarm;
117 int barWidth;
119 } BarGraph_t;
122 * Private data holder
124 typedef struct
126 vlc_blender_t *p_blend;
128 vlc_mutex_t lock;
130 BarGraph_t p_BarGraph;
132 int i_pos;
133 int i_pos_x;
134 int i_pos_y;
135 bool b_absolute;
137 /* On the fly control variable */
138 bool b_spu_update;
139 } filter_sys_t;
141 static const char *const ppsz_filter_options[] = {
142 "x", "y", "transparency", "position", "barWidth", "barHeight", NULL
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 "audiobargraph_v-barHeight",
152 NULL
155 /*****************************************************************************
156 * IEC 268-18 Source: meterbridge
157 *****************************************************************************/
158 static float iec_scale(float dB)
160 if (dB < -70.0f)
161 return 0.0f;
162 if (dB < -60.0f)
163 return (dB + 70.0f) * 0.0025f;
164 if (dB < -50.0f)
165 return (dB + 60.0f) * 0.005f + 0.025f;
166 if (dB < -40.0f)
167 return (dB + 50.0f) * 0.0075f + 0.075f;
168 if (dB < -30.0f)
169 return (dB + 40.0f) * 0.015f + 0.15f;
170 if (dB < -20.0f)
171 return (dB + 30.0f) * 0.02f + 0.3f;
172 if (dB < -0.001f || dB > 0.001f) /* if (dB < 0.0f) */
173 return (dB + 20.0f) * 0.025f + 0.5f;
174 return 1.0f;
177 /*****************************************************************************
178 * parse_i_values : parse i_values parameter and store the corresponding values
179 *****************************************************************************/
180 static void parse_i_values(BarGraph_t *p_BarGraph, char *i_values)
182 char delim[] = ":";
183 char* tok;
185 p_BarGraph->nbChannels = 0;
186 free(p_BarGraph->i_values);
187 p_BarGraph->i_values = NULL;
188 char *res = strtok_r(i_values, delim, &tok);
189 while (res != NULL) {
190 p_BarGraph->nbChannels++;
191 p_BarGraph->i_values = xrealloc(p_BarGraph->i_values,
192 p_BarGraph->nbChannels*sizeof(int));
193 float db = log10(atof(res)) * 20;
194 p_BarGraph->i_values[p_BarGraph->nbChannels-1] = VLC_CLIP(iec_scale(db)*p_BarGraph->scale, 0, p_BarGraph->scale);
195 res = strtok_r(NULL, delim, &tok);
199 /* Drawing */
201 static const uint8_t bright_red[4] = { 76, 85, 0xff, 0xff };
202 static const uint8_t black[4] = { 0x00, 0x80, 0x80, 0xff };
203 static const uint8_t white[4] = { 0xff, 0x80, 0x80, 0xff };
204 static const uint8_t bright_green[4] = { 150, 44, 21, 0xff };
205 static const uint8_t bright_yellow[4] = { 226, 1, 148, 0xff };
206 static const uint8_t green[4] = { 74, 85, 74, 0xff };
207 static const uint8_t yellow[4] = { 112, 64, 138, 0xff };
208 static const uint8_t red[4] = { 37, 106, 191, 0xff };
210 static inline void DrawHLine(plane_t *p, int line, int col, const uint8_t color[4], int w)
212 for (int j = 0; j < 4; j++)
213 memset(&p[j].p_pixels[line * p[j].i_pitch + col], color[j], w);
216 static void Draw2VLines(plane_t *p, int scale, int col, const uint8_t color[4])
218 for (int i = 10; i < scale + 10; i++)
219 DrawHLine(p, i, col, color, 2);
222 static void DrawHLines(plane_t *p, int line, int col, const uint8_t color[4], int h, int w)
224 for (int i = line; i < line + h; i++)
225 DrawHLine(p, i, col, color, w);
228 static void DrawNumber(plane_t *p, int h, const uint8_t data[5], int l)
230 for (int i = 0; i < 5; i++) {
231 uint8_t x = data[i];
232 for (int j = 0; j < 7; j++) {
233 x <<= 1;
234 if (x & 0x80)
235 DrawHLine(p, h - l + 2 - 1 - i, 12 + j, black, 1);
239 /*****************************************************************************
240 * Draw: creates and returns the bar graph image
241 *****************************************************************************/
242 static void Draw(BarGraph_t *b)
244 int nbChannels = b->nbChannels;
245 int scale = b->scale;
246 int barWidth = b->barWidth;
248 int w = 40;
249 if (nbChannels > 0)
250 w = 2 * nbChannels * barWidth + 30;
251 int h = scale + 30;
253 int level[6];
254 for (int i = 0; i < 6; i++)
255 level[i] = iec_scale(-(i+1) * 10) * scale + 20;
257 if (b->p_pic)
258 picture_Release(b->p_pic);
259 b->p_pic = picture_New(VLC_FOURCC('Y','U','V','A'), w, h, 1, 1);
260 if (!b->p_pic)
261 return;
262 picture_t *p_pic = b->p_pic;
263 plane_t *p = p_pic->p;
265 for (int i = 0 ; i < p_pic->i_planes ; i++)
266 memset(p[i].p_pixels, 0x00, p[i].i_visible_lines * p[i].i_pitch);
268 Draw2VLines(p, scale, 20, black);
269 Draw2VLines(p, scale, 22, white);
271 static const uint8_t pixmap[6][5] = {
272 { 0x17, 0x15, 0x15, 0x15, 0x17 },
273 { 0x77, 0x45, 0x75, 0x15, 0x77 },
274 { 0x77, 0x15, 0x75, 0x15, 0x77 },
275 { 0x17, 0x15, 0x75, 0x55, 0x57 },
276 { 0x77, 0x15, 0x75, 0x45, 0x77 },
277 { 0x77, 0x55, 0x75, 0x45, 0x77 },
280 for (int i = 0; i < 6; i++) {
281 DrawHLines(p, h - 1 - level[i] - 1, 24, white, 1, 3);
282 DrawHLines(p, h - 1 - level[i], 24, black, 2, 3);
283 DrawNumber(p, h, pixmap[i], level[i]);
286 int minus8 = iec_scale(- 8) * scale + 20;
287 int minus18 = iec_scale(-18) * scale + 20;
288 int *i_values = b->i_values;
289 const uint8_t *indicator_color = b->alarm ? bright_red : black;
291 for (int i = 0; i < nbChannels; i++) {
292 int pi = 30 + i * (5 + barWidth);
294 DrawHLines(p, h - 20 - 1, pi, indicator_color, 8, barWidth);
296 for (int line = 20; line < i_values[i] + 20; line++) {
297 if (line < minus18)
298 DrawHLines(p, h - line - 1, pi, bright_green, 1, barWidth);
299 else if (line < minus8)
300 DrawHLines(p, h - line - 1, pi, bright_yellow, 1, barWidth);
301 else
302 DrawHLines(p, h - line - 1, pi, bright_red, 1, barWidth);
305 for (int line = i_values[i] + 20; line < scale + 20; line++) {
306 if (line < minus18)
307 DrawHLines(p, h - line - 1, pi, green, 1, barWidth);
308 else if (line < minus8)
309 DrawHLines(p, h - line - 1, pi, yellow, 1, barWidth);
310 else
311 DrawHLines(p, h - line - 1, pi, red, 1, barWidth);
316 /*****************************************************************************
317 * Callback to update params on the fly
318 *****************************************************************************/
319 static int BarGraphCallback(vlc_object_t *p_this, char const *psz_var,
320 vlc_value_t oldval, vlc_value_t newval, void *p_data)
322 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
323 filter_sys_t *p_sys = p_data;
324 BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
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 if (newval.psz_string)
337 parse_i_values(p_BarGraph, newval.psz_string);
338 Draw(p_BarGraph);
339 } else if (!strcmp(psz_var, CFG_PREFIX "alarm")) {
340 p_BarGraph->alarm = newval.b_bool;
341 Draw(p_BarGraph);
342 } else if (!strcmp(psz_var, CFG_PREFIX "barWidth")) {
343 p_BarGraph->barWidth = newval.i_int;
344 Draw(p_BarGraph);
345 } else if (!strcmp(psz_var, CFG_PREFIX "barHeight")) {
346 p_BarGraph->scale = newval.i_int;
347 Draw(p_BarGraph);
349 p_sys->b_spu_update = true;
350 vlc_mutex_unlock(&p_sys->lock);
352 return VLC_SUCCESS;
356 * Sub source
358 static subpicture_t *FilterSub(filter_t *p_filter, vlc_tick_t date)
360 filter_sys_t *p_sys = p_filter->p_sys;
361 BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
363 subpicture_t *p_spu;
364 subpicture_region_t *p_region;
365 video_format_t fmt;
366 picture_t *p_pic;
368 vlc_mutex_lock(&p_sys->lock);
369 /* Basic test: b_spu_update occurs on a dynamic change */
370 if (!p_sys->b_spu_update) {
371 vlc_mutex_unlock(&p_sys->lock);
372 return NULL;
375 p_pic = p_BarGraph->p_pic;
377 /* Allocate the subpicture internal data. */
378 p_spu = filter_NewSubpicture(p_filter);
379 if (!p_spu)
380 goto exit;
382 p_spu->b_absolute = p_sys->b_absolute;
383 p_spu->i_start = date;
384 p_spu->i_stop = 0;
385 p_spu->b_ephemer = true;
387 /* Send an empty subpicture to clear the display when needed */
388 if (!p_pic || !p_BarGraph->i_alpha)
389 goto exit;
391 /* Create new SPU region */
392 video_format_Init(&fmt, VLC_CODEC_YUVA);
393 fmt.i_sar_num = fmt.i_sar_den = 1;
394 fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
395 fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
396 fmt.i_x_offset = fmt.i_y_offset = 0;
397 p_region = subpicture_region_New(&fmt);
398 if (!p_region) {
399 msg_Err(p_filter, "cannot allocate SPU region");
400 subpicture_Delete(p_spu);
401 p_spu = NULL;
402 goto exit;
405 /* */
406 picture_Copy(p_region->p_picture, p_pic);
408 /* where to locate the bar graph: */
409 if (p_sys->i_pos < 0) { /* set to an absolute xy */
410 p_region->i_align = SUBPICTURE_ALIGN_RIGHT | SUBPICTURE_ALIGN_TOP;
411 p_spu->b_absolute = true;
412 } else { /* set to one of the 9 relative locations */
413 p_region->i_align = p_sys->i_pos;
414 p_spu->b_absolute = false;
417 p_region->i_x = p_sys->i_pos_x;
418 p_region->i_y = p_sys->i_pos_y;
420 p_spu->p_region = p_region;
422 p_spu->i_alpha = p_BarGraph->i_alpha ;
424 exit:
425 vlc_mutex_unlock(&p_sys->lock);
427 return p_spu;
431 * Video filter
433 static picture_t *FilterVideo(filter_t *p_filter, picture_t *p_src)
435 filter_sys_t *p_sys = p_filter->p_sys;
436 BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph);
438 picture_t *p_dst = filter_NewPicture(p_filter);
439 if (!p_dst) {
440 picture_Release(p_src);
441 return NULL;
444 picture_Copy(p_dst, p_src);
446 /* */
447 vlc_mutex_lock(&p_sys->lock);
449 /* */
450 const picture_t *p_pic = p_BarGraph->p_pic;
451 if (!p_pic)
452 goto out;
454 const video_format_t *p_fmt = &p_pic->format;
455 const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
456 const int i_dst_h = p_filter->fmt_out.video.i_visible_height;
458 if (p_sys->i_pos) {
459 if (p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM)
460 p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
461 else if (!(p_sys->i_pos & SUBPICTURE_ALIGN_TOP))
462 p_sys->i_pos_y = (i_dst_h - p_fmt->i_visible_height) / 2;
463 else
464 p_sys->i_pos_y = 0;
466 if (p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT)
467 p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
468 else if (!(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT))
469 p_sys->i_pos_x = (i_dst_w - p_fmt->i_visible_width) / 2;
470 else
471 p_sys->i_pos_x = 0;
474 /* */
475 const int i_alpha = p_BarGraph->i_alpha;
476 if (filter_ConfigureBlend(p_sys->p_blend, i_dst_w, i_dst_h, p_fmt) ||
477 filter_Blend(p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
478 p_pic, i_alpha))
479 msg_Err(p_filter, "failed to blend a picture");
481 out:
482 vlc_mutex_unlock(&p_sys->lock);
484 picture_Release(p_src);
485 return p_dst;
488 static const struct vlc_filter_operations filter_sub_ops = {
489 .source_sub = FilterSub, .close = Close
492 static const struct vlc_filter_operations filter_video_ops = {
493 .filter_video = FilterVideo, .close = Close,
497 * Common open function
499 static int OpenCommon(filter_t *p_filter, bool b_sub)
501 filter_sys_t *p_sys;
503 /* */
504 if (!b_sub && !es_format_IsSimilar(&p_filter->fmt_in, &p_filter->fmt_out)) {
505 msg_Err(p_filter, "Input and output format does not match");
506 return VLC_EGENERIC;
510 /* */
511 p_filter->p_sys = p_sys = malloc(sizeof(*p_sys));
512 if (!p_sys)
513 return VLC_ENOMEM;
515 /* */
516 p_sys->p_blend = NULL;
517 if (!b_sub) {
518 p_sys->p_blend = filter_NewBlend(VLC_OBJECT(p_filter),
519 &p_filter->fmt_in.video);
520 if (!p_sys->p_blend) {
521 free(p_sys);
522 return VLC_EGENERIC;
526 /* */
527 config_ChainParse(p_filter, CFG_PREFIX, ppsz_filter_options,
528 p_filter->p_cfg);
530 /* create and initialize variables */
531 p_sys->i_pos = var_CreateGetInteger(p_filter, CFG_PREFIX "position");
532 p_sys->i_pos_x = var_CreateGetInteger(p_filter, CFG_PREFIX "x");
533 p_sys->i_pos_y = var_CreateGetInteger(p_filter, CFG_PREFIX "y");
534 BarGraph_t *p_BarGraph = &p_sys->p_BarGraph;
535 p_BarGraph->p_pic = NULL;
536 p_BarGraph->i_alpha = var_CreateGetInteger(p_filter, CFG_PREFIX "transparency");
537 p_BarGraph->i_alpha = VLC_CLIP(p_BarGraph->i_alpha, 0, 255);
538 p_BarGraph->i_values = NULL;
539 parse_i_values(p_BarGraph, &(char){ 0 });
540 p_BarGraph->alarm = false;
542 p_BarGraph->barWidth = var_CreateGetInteger(p_filter, CFG_PREFIX "barWidth");
543 p_BarGraph->scale = var_CreateGetInteger( p_filter, CFG_PREFIX "barHeight");
545 /* Ignore aligment if a position is given for video filter */
546 if (!b_sub && p_sys->i_pos_x >= 0 && p_sys->i_pos_y >= 0)
547 p_sys->i_pos = 0;
549 vlc_object_t *vlc = VLC_OBJECT(vlc_object_instance(p_filter));
551 vlc_mutex_init(&p_sys->lock);
552 var_Create(vlc, CFG_PREFIX "alarm", VLC_VAR_BOOL);
553 var_Create(vlc, CFG_PREFIX "i_values", VLC_VAR_STRING);
555 var_AddCallback(vlc, CFG_PREFIX "alarm", BarGraphCallback, p_sys);
556 var_AddCallback(vlc, CFG_PREFIX "i_values", BarGraphCallback, p_sys);
558 var_TriggerCallback(vlc, CFG_PREFIX "alarm");
559 var_TriggerCallback(vlc, CFG_PREFIX "i_values");
561 for (int i = 0; ppsz_filter_callbacks[i]; i++)
562 var_AddCallback(p_filter, ppsz_filter_callbacks[i],
563 BarGraphCallback, p_sys);
565 if (b_sub)
566 p_filter->ops = &filter_sub_ops;
567 else
568 p_filter->ops = &filter_video_ops;
570 return VLC_SUCCESS;
574 * Open the sub source
576 static int OpenSub(filter_t *p_filter)
578 return OpenCommon(p_filter, true);
582 * Open the video filter
584 static int OpenVideo(filter_t *p_filter)
586 return OpenCommon(p_filter, false);
590 * Common close function
592 static void Close(filter_t *p_filter)
594 filter_sys_t *p_sys = p_filter->p_sys;
595 vlc_object_t *vlc = VLC_OBJECT(vlc_object_instance(p_filter));
597 for (int i = 0; ppsz_filter_callbacks[i]; i++)
598 var_DelCallback(p_filter, ppsz_filter_callbacks[i],
599 BarGraphCallback, p_sys);
601 var_DelCallback(vlc, CFG_PREFIX "i_values", BarGraphCallback, p_sys);
602 var_DelCallback(vlc, CFG_PREFIX "alarm", BarGraphCallback, p_sys);
603 var_Destroy(vlc, CFG_PREFIX "i_values");
604 var_Destroy(vlc, CFG_PREFIX "alarm");
606 if (p_sys->p_blend)
607 filter_DeleteBlend(p_sys->p_blend);
609 if (p_sys->p_BarGraph.p_pic)
610 picture_Release(p_sys->p_BarGraph.p_pic);
612 free(p_sys->p_BarGraph.i_values);
614 free(p_sys);