summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfred E. Heggestad <aeh@db.org>2015-10-25 13:11:32 +0100
committerAlfred E. Heggestad <aeh@db.org>2015-10-25 13:11:32 +0100
commit558b17a21f0e740b8293259483649f4d38c5703d (patch)
tree5a8ccdcbfc429b1a14f0229ab113e0221a730e21
parent0700413f8676ca7224250cdfabf4af7aaedb3bf9 (diff)
vidinfo: new module for displaying video-info
- implemented as a video-filter (vidfilt) - displays information about the current video stream, like encode/decode FPS and a graph of timing information
-rw-r--r--modules/vidinfo/module.mk11
-rw-r--r--modules/vidinfo/panel.c288
-rw-r--r--modules/vidinfo/vidinfo.c167
-rw-r--r--modules/vidinfo/vidinfo.h42
4 files changed, 508 insertions, 0 deletions
diff --git a/modules/vidinfo/module.mk b/modules/vidinfo/module.mk
new file mode 100644
index 0000000..b80c3a4
--- /dev/null
+++ b/modules/vidinfo/module.mk
@@ -0,0 +1,11 @@
+#
+# module.mk
+#
+# Copyright (C) 2010 Creytiv.com
+#
+
+MOD := vidinfo
+$(MOD)_SRCS += vidinfo.c panel.c
+$(MOD)_LFLAGS += -lcairo
+
+include mk/mod.mk
diff --git a/modules/vidinfo/panel.c b/modules/vidinfo/panel.c
new file mode 100644
index 0000000..a5e7c6c
--- /dev/null
+++ b/modules/vidinfo/panel.c
@@ -0,0 +1,288 @@
+/**
+ * @file panel.c Video-info filter -- panel
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "vidinfo.h"
+
+
+static void rrd_append(struct panel *panel, uint64_t val)
+{
+ if (!panel)
+ return;
+
+ panel->rrdv[panel->rrdc++] = val;
+ panel->rrd_sum += val;
+
+ if (panel->rrdc >= panel->rrdsz) {
+ panel->rrdc = 0;
+ panel->rrd_sum = 0;
+ }
+}
+
+
+static int rrd_get_average(struct panel *panel, uint64_t *average)
+{
+ if (!panel->rrdc)
+ return ENOENT;
+
+ *average = panel->rrd_sum / panel->rrdc;
+
+ return 0;
+}
+
+
+static void tmr_handler(void *arg)
+{
+ struct panel *panel = arg;
+ uint64_t now = tmr_jiffies();
+
+ tmr_start(&panel->tmr, 2000, tmr_handler, panel);
+
+ if (panel->ts) {
+ panel->fps = 1000.0 * panel->nframes / (now - panel->ts);
+ }
+ panel->nframes = 0;
+
+ panel->ts = now;
+}
+
+
+static void destructor(void *arg)
+{
+ struct panel *panel = arg;
+
+ tmr_cancel(&panel->tmr);
+ mem_deref(panel->label);
+ mem_deref(panel->rrdv);
+
+ if (panel->cr)
+ cairo_destroy(panel->cr);
+ if (panel->surface)
+ cairo_surface_destroy(panel->surface);
+}
+
+
+int panel_alloc(struct panel **panelp, const char *label,
+ unsigned yoffs, int width, int height)
+{
+ struct panel *panel;
+ int err;
+
+ if (!panelp || !width || !height)
+ return EINVAL;
+
+ panel = mem_zalloc(sizeof(*panel), destructor);
+ if (!panel)
+ return ENOMEM;
+
+ err = str_dup(&panel->label, label);
+ if (err)
+ goto out;
+
+ panel->size.w = width;
+ panel->size.h = height;
+ panel->yoffs = yoffs;
+ panel->xoffs = TEXT_WIDTH;
+
+ panel->size_text.w = TEXT_WIDTH;
+ panel->size_text.h = height;
+
+ panel->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ panel->size_text.w,
+ panel->size_text.h);
+ panel->cr = cairo_create(panel->surface);
+ if (!panel->surface || !panel->cr) {
+ warning("vidinfo: cairo error\n");
+ return ENOMEM;
+ }
+
+ cairo_select_font_face (panel->cr, "Hyperfont",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (panel->cr, height-2);
+
+ panel->rrdc = 0;
+ panel->rrdsz = (width - TEXT_WIDTH) / 2;
+ panel->rrdv = mem_reallocarray(NULL, panel->rrdsz,
+ sizeof(*panel->rrdv), NULL);
+ if (!panel->rrdv) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ tmr_start(&panel->tmr, 0, tmr_handler, panel);
+
+ info("new panel '%s' (%u x %u) with RRD size %u\n",
+ label, width, height, panel->rrdsz);
+
+ out:
+ if (err)
+ mem_deref(panel);
+ else
+ *panelp = panel;
+
+ return err;
+}
+
+
+static void overlay(struct vidframe *dst, unsigned yoffs, struct vidframe *src)
+{
+ uint8_t *pdst, *psrc;
+ unsigned x, y;
+
+ pdst = dst->data[0] + yoffs * dst->linesize[0];
+ psrc = src->data[0];
+
+ for (y=0; y<src->size.h; y++) {
+
+ for (x=0; x<src->size.w; x++) {
+
+ if (psrc[x] > 127)
+ pdst[x] = psrc[x];
+ }
+
+ pdst += dst->linesize[0];
+ psrc += src->linesize[0];
+ }
+}
+
+
+static int draw_text(struct panel *panel, struct vidframe *frame)
+{
+ char buf[256];
+ int width = panel->size_text.w;
+ int height = panel->size_text.h;
+ struct vidframe f;
+ struct vidframe *f2 = NULL;
+ cairo_t *cr = panel->cr;
+ double tx, ty;
+ int err;
+
+ tx = 1;
+ ty = height - 3;
+
+ /* draw background */
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_fill (cr);
+
+ /* Draw text */
+ if (re_snprintf(buf, sizeof(buf), "%s %2.2f fps",
+ panel->label, panel->fps) < 0)
+ return ENOMEM;
+
+ cairo_move_to (cr, tx, ty);
+ cairo_text_path (cr, buf);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_fill_preserve (cr);
+ cairo_set_line_width (cr, 0.6);
+ cairo_stroke (cr);
+
+ vidframe_init_buf(&f, VID_FMT_ARGB, &panel->size_text,
+ cairo_image_surface_get_data(panel->surface));
+
+ err = vidframe_alloc(&f2, frame->fmt, &panel->size_text);
+ if (err)
+ goto out;
+
+ vidconv(f2, &f, 0);
+
+ overlay(frame, panel->yoffs, f2);
+
+ out:
+ mem_deref(f2);
+ return err;
+}
+
+
+static void dim_frame(struct vidframe *frame, unsigned yoffs, unsigned height)
+{
+ unsigned x, y;
+ uint8_t *p;
+ bool lower = (yoffs > 0);
+ double grade = lower ? 1.00 : (1.00 - PANEL_HEIGHT/100.0);
+
+ p = frame->data[0] + yoffs * frame->linesize[0];
+
+ /* first dim the background */
+ for (y = 0; y < height; y++) {
+
+ for (x = 0; x < frame->size.w; x++) {
+ p[x] = p[x] * grade;
+ }
+
+ p += frame->linesize[0];
+
+ if (lower)
+ grade -= 0.01;
+ else
+ grade += 0.01;
+ }
+}
+
+
+static void draw_graph(struct panel *panel, struct vidframe *frame)
+{
+ uint64_t avg;
+ unsigned y0 = panel->yoffs;
+ size_t i;
+
+ if (rrd_get_average(panel, &avg))
+ return;
+
+ for (i=0; i<panel->rrdc; i++) {
+
+ uint64_t value;
+ double ratio;
+ unsigned pixels;
+ unsigned x = panel->xoffs + (unsigned)i * 2;
+ unsigned y;
+ value = panel->rrdv[i];
+
+ ratio = (double)value / (double)avg;
+
+ pixels = (double)panel->size.h * ratio * 0.5f;
+
+ pixels = min(pixels, panel->size.h);
+
+ y = y0 + panel->size.h - pixels;
+
+ vidframe_draw_vline(frame, x, y, pixels, 220, 220, 220);
+ }
+}
+
+
+int panel_draw(struct panel *panel, struct vidframe *frame)
+{
+ int err;
+
+ if (!panel || !frame)
+ return EINVAL;
+
+ dim_frame(frame, panel->yoffs, panel->size.h);
+
+ err = draw_text(panel, frame);
+ if (err)
+ return err;
+ draw_graph(panel, frame);
+
+ return 0;
+}
+
+
+void panel_add_frame(struct panel *panel, uint64_t pts)
+{
+ if (!panel)
+ return;
+
+ if (panel->pts_prev) {
+ rrd_append(panel, pts - panel->pts_prev);
+ }
+
+ panel->nframes++;
+ panel->pts_prev = pts;
+}
diff --git a/modules/vidinfo/vidinfo.c b/modules/vidinfo/vidinfo.c
new file mode 100644
index 0000000..9063a3f
--- /dev/null
+++ b/modules/vidinfo/vidinfo.c
@@ -0,0 +1,167 @@
+/**
+ * @file vidinfo.c Video-info filter
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "vidinfo.h"
+
+
+struct vidinfo_enc {
+ struct vidfilt_enc_st vf; /* base member (inheritance) */
+
+ struct panel *panel;
+};
+
+
+struct vidinfo_dec {
+ struct vidfilt_dec_st vf; /* base member (inheritance) */
+
+ struct panel *panel;
+};
+
+
+static void encode_destructor(void *arg)
+{
+ struct vidinfo_enc *st = arg;
+
+ list_unlink(&st->vf.le);
+ mem_deref(st->panel);
+}
+
+
+static void decode_destructor(void *arg)
+{
+ struct vidinfo_dec *st = arg;
+
+ list_unlink(&st->vf.le);
+ mem_deref(st->panel);
+}
+
+
+static int encode_update(struct vidfilt_enc_st **stp, void **ctx,
+ const struct vidfilt *vf)
+{
+ struct vidinfo_enc *st;
+ int err = 0;
+
+ if (!stp || !ctx || !vf)
+ return EINVAL;
+
+ if (*stp)
+ return 0;
+
+ st = mem_zalloc(sizeof(*st), encode_destructor);
+ if (!st)
+ return ENOMEM;
+
+ if (err)
+ mem_deref(st);
+ else
+ *stp = (struct vidfilt_enc_st *)st;
+
+ return err;
+}
+
+
+static int decode_update(struct vidfilt_dec_st **stp, void **ctx,
+ const struct vidfilt *vf)
+{
+ struct vidinfo_dec *st;
+ int err = 0;
+
+ if (!stp || !ctx || !vf)
+ return EINVAL;
+
+ if (*stp)
+ return 0;
+
+ st = mem_zalloc(sizeof(*st), decode_destructor);
+ if (!st)
+ return ENOMEM;
+
+ if (err)
+ mem_deref(st);
+ else
+ *stp = (struct vidfilt_dec_st *)st;
+
+ return err;
+}
+
+
+static int encode(struct vidfilt_enc_st *_st, struct vidframe *frame)
+{
+ struct vidinfo_enc *st = (struct vidinfo_enc *)_st;
+ int err = 0;
+
+ if (!st->panel) {
+
+ unsigned width = frame->size.w;
+ unsigned height = MIN(PANEL_HEIGHT, frame->size.h);
+
+ err = panel_alloc(&st->panel, "encode", 0, width, height);
+ if (err)
+ return err;
+ }
+
+ panel_add_frame(st->panel, tmr_jiffies());
+
+ panel_draw(st->panel, frame);
+
+ return 0;
+}
+
+
+static int decode(struct vidfilt_dec_st *_st, struct vidframe *frame)
+{
+ struct vidinfo_dec *st = (struct vidinfo_dec *)_st;
+ int err = 0;
+
+ if (!st->panel) {
+
+ unsigned width = frame->size.w;
+ unsigned height = MIN(PANEL_HEIGHT, frame->size.h);
+ unsigned yoffs = frame->size.h - PANEL_HEIGHT;
+
+ err = panel_alloc(&st->panel, "decode", yoffs, width, height);
+ if (err)
+ return err;
+ }
+
+ panel_add_frame(st->panel, tmr_jiffies());
+
+ panel_draw(st->panel, frame);
+
+ return 0;
+}
+
+
+static struct vidfilt vidinfo = {
+ LE_INIT, "vidinfo", encode_update, encode, decode_update, decode
+};
+
+
+static int module_init(void)
+{
+ vidfilt_register(&vidinfo);
+
+ return 0;
+}
+
+
+static int module_close(void)
+{
+ vidfilt_unregister(&vidinfo);
+
+ return 0;
+}
+
+
+EXPORT_SYM const struct mod_export DECL_EXPORTS(vidinfo) = {
+ "vidinfo",
+ "vidfilt",
+ module_init,
+ module_close
+};
diff --git a/modules/vidinfo/vidinfo.h b/modules/vidinfo/vidinfo.h
new file mode 100644
index 0000000..7f540e4
--- /dev/null
+++ b/modules/vidinfo/vidinfo.h
@@ -0,0 +1,42 @@
+/**
+ * @file vidinfo.h Video-info filter
+ *
+ * Copyright (C) 2010 - 2015 Creytiv.com
+ */
+
+
+#include <cairo/cairo.h>
+
+
+#define PANEL_HEIGHT 24
+#define TEXT_WIDTH 220
+
+
+struct panel {
+ struct vidsz size;
+ struct vidsz size_text;
+ unsigned yoffs;
+ unsigned xoffs;
+ char *label;
+
+ uint64_t *rrdv;
+ size_t rrdsz;
+ size_t rrdc;
+ uint64_t rrd_sum;
+
+ unsigned nframes;
+ uint64_t ts;
+ double fps;
+ struct tmr tmr;
+
+ uint64_t pts_prev;
+
+ /* cairo backend: */
+ cairo_surface_t *surface;
+ cairo_t *cr;
+};
+
+int panel_alloc(struct panel **panelp, const char *label,
+ unsigned yoffs, int width, int height);
+void panel_add_frame(struct panel *panel, uint64_t pts);
+int panel_draw(struct panel *panel, struct vidframe *frame);