1 /**
2 * @file panel.c Video-info filter -- panel
3 *
4 * Copyright (C) 2010 - 2015 Creytiv.com
5 */
6 #include <re.h>
7 #include <rem.h>
8 #include <baresip.h>
9 #include "vidinfo.h"
10
11
rrd_append(struct panel * panel,uint64_t val)12 static void rrd_append(struct panel *panel, uint64_t val)
13 {
14 if (!panel)
15 return;
16
17 panel->rrdv[panel->rrdc++] = val;
18 panel->rrd_sum += val;
19
20 if (panel->rrdc >= panel->rrdsz) {
21 panel->rrdc = 0;
22 panel->rrd_sum = 0;
23 }
24 }
25
26
rrd_get_average(struct panel * panel,uint64_t * average)27 static int rrd_get_average(struct panel *panel, uint64_t *average)
28 {
29 if (!panel->rrdc)
30 return ENOENT;
31
32 *average = panel->rrd_sum / panel->rrdc;
33
34 return 0;
35 }
36
37
tmr_handler(void * arg)38 static void tmr_handler(void *arg)
39 {
40 struct panel *panel = arg;
41 uint64_t now = tmr_jiffies();
42
43 tmr_start(&panel->tmr, 2000, tmr_handler, panel);
44
45 if (panel->ts) {
46 panel->fps = 1000.0 * panel->nframes / (now - panel->ts);
47 }
48 panel->nframes = 0;
49
50 panel->ts = now;
51 }
52
53
destructor(void * arg)54 static void destructor(void *arg)
55 {
56 struct panel *panel = arg;
57
58 tmr_cancel(&panel->tmr);
59 mem_deref(panel->label);
60 mem_deref(panel->rrdv);
61
62 if (panel->cr)
63 cairo_destroy(panel->cr);
64 if (panel->surface)
65 cairo_surface_destroy(panel->surface);
66 }
67
68
panel_alloc(struct panel ** panelp,const char * label,unsigned yoffs,int width,int height)69 int panel_alloc(struct panel **panelp, const char *label,
70 unsigned yoffs, int width, int height)
71 {
72 struct panel *panel;
73 int err;
74
75 if (!panelp || !width || !height)
76 return EINVAL;
77
78 panel = mem_zalloc(sizeof(*panel), destructor);
79 if (!panel)
80 return ENOMEM;
81
82 err = str_dup(&panel->label, label);
83 if (err)
84 goto out;
85
86 panel->size.w = width;
87 panel->size.h = height;
88 panel->yoffs = yoffs;
89 panel->xoffs = TEXT_WIDTH;
90
91 panel->size_text.w = TEXT_WIDTH;
92 panel->size_text.h = height;
93
94 panel->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
95 panel->size_text.w,
96 panel->size_text.h);
97 panel->cr = cairo_create(panel->surface);
98 if (!panel->surface || !panel->cr) {
99 warning("vidinfo: cairo error\n");
100 return ENOMEM;
101 }
102
103 cairo_select_font_face (panel->cr, "Hyperfont",
104 CAIRO_FONT_SLANT_NORMAL,
105 CAIRO_FONT_WEIGHT_NORMAL);
106 cairo_set_font_size (panel->cr, height-2);
107
108 panel->rrdc = 0;
109 panel->rrdsz = (width - TEXT_WIDTH) / 2;
110 panel->rrdv = mem_reallocarray(NULL, panel->rrdsz,
111 sizeof(*panel->rrdv), NULL);
112 if (!panel->rrdv) {
113 err = ENOMEM;
114 goto out;
115 }
116
117 tmr_start(&panel->tmr, 0, tmr_handler, panel);
118
119 info("new panel '%s' (%u x %u) with RRD size %u\n",
120 label, width, height, panel->rrdsz);
121
122 out:
123 if (err)
124 mem_deref(panel);
125 else
126 *panelp = panel;
127
128 return err;
129 }
130
131
overlay(struct vidframe * dst,unsigned yoffs,struct vidframe * src)132 static void overlay(struct vidframe *dst, unsigned yoffs, struct vidframe *src)
133 {
134 uint8_t *pdst, *psrc;
135 unsigned x, y;
136
137 pdst = dst->data[0] + yoffs * dst->linesize[0];
138 psrc = src->data[0];
139
140 for (y=0; y<src->size.h; y++) {
141
142 for (x=0; x<src->size.w; x++) {
143
144 /* copy the luma component if visible */
145 if (psrc[x] > 16)
146 pdst[x] = psrc[x];
147 }
148
149 pdst += dst->linesize[0];
150 psrc += src->linesize[0];
151 }
152 }
153
154
draw_text(struct panel * panel,struct vidframe * frame)155 static int draw_text(struct panel *panel, struct vidframe *frame)
156 {
157 char buf[256];
158 int width = panel->size_text.w;
159 int height = panel->size_text.h;
160 struct vidframe f;
161 struct vidframe *f2 = NULL;
162 cairo_t *cr = panel->cr;
163 double tx, ty;
164 int err;
165
166 tx = 1;
167 ty = height - 3;
168
169 /* draw background */
170 cairo_rectangle (cr, 0, 0, width, height);
171 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
172 cairo_fill (cr);
173
174 /* Draw text */
175 if (re_snprintf(buf, sizeof(buf), "%s %2.2f fps",
176 panel->label, panel->fps) < 0)
177 return ENOMEM;
178
179 cairo_move_to (cr, tx, ty);
180 cairo_text_path (cr, buf);
181 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
182 cairo_fill_preserve (cr);
183 cairo_set_line_width (cr, 0.6);
184 cairo_stroke (cr);
185
186 vidframe_init_buf(&f, VID_FMT_RGB32, &panel->size_text,
187 cairo_image_surface_get_data(panel->surface));
188
189 err = vidframe_alloc(&f2, frame->fmt, &panel->size_text);
190 if (err)
191 goto out;
192
193 vidconv(f2, &f, 0);
194
195 overlay(frame, panel->yoffs, f2);
196
197 out:
198 mem_deref(f2);
199 return err;
200 }
201
202
dim_frame(struct vidframe * frame,unsigned yoffs,unsigned height)203 static void dim_frame(struct vidframe *frame, unsigned yoffs, unsigned height)
204 {
205 unsigned x, y;
206 uint8_t *p;
207 bool lower = (yoffs > 0);
208 double grade = lower ? 1.00 : (1.00 - PANEL_HEIGHT/100.0);
209
210 p = frame->data[0] + yoffs * frame->linesize[0];
211
212 /* first dim the background */
213 for (y = 0; y < height; y++) {
214
215 for (x = 0; x < frame->size.w; x++) {
216 p[x] = p[x] * grade;
217 }
218
219 p += frame->linesize[0];
220
221 if (lower)
222 grade -= 0.01;
223 else
224 grade += 0.01;
225 }
226 }
227
228
draw_graph(struct panel * panel,struct vidframe * frame)229 static void draw_graph(struct panel *panel, struct vidframe *frame)
230 {
231 uint64_t avg;
232 unsigned y0 = panel->yoffs;
233 size_t i;
234
235 if (rrd_get_average(panel, &avg))
236 return;
237
238 for (i=0; i<panel->rrdc; i++) {
239
240 uint64_t value;
241 double ratio;
242 unsigned pixels;
243 unsigned x = panel->xoffs + (unsigned)i * 2;
244 unsigned y;
245 value = panel->rrdv[i];
246
247 ratio = (double)value / (double)avg;
248
249 pixels = (unsigned)((double)panel->size.h * ratio * 0.5f);
250
251 pixels = min(pixels, panel->size.h);
252
253 y = y0 + panel->size.h - pixels;
254
255 vidframe_draw_vline(frame, x, y, pixels, 220, 220, 220);
256 }
257 }
258
259
panel_draw(struct panel * panel,struct vidframe * frame)260 int panel_draw(struct panel *panel, struct vidframe *frame)
261 {
262 int err;
263
264 if (!panel || !frame)
265 return EINVAL;
266
267 dim_frame(frame, panel->yoffs, panel->size.h);
268
269 err = draw_text(panel, frame);
270 if (err)
271 return err;
272 draw_graph(panel, frame);
273
274 return 0;
275 }
276
277
panel_add_frame(struct panel * panel,uint64_t pts)278 void panel_add_frame(struct panel *panel, uint64_t pts)
279 {
280 if (!panel)
281 return;
282
283 if (panel->pts_prev) {
284 rrd_append(panel, pts - panel->pts_prev);
285 }
286
287 panel->nframes++;
288 panel->pts_prev = pts;
289 }
290