├── .gitignore ├── debian ├── source │ └── format ├── rules ├── upstream │ └── metadata ├── changelog ├── copyright └── control ├── .github ├── FUNDING.yml └── workflows │ ├── package-debian-deb.yaml │ └── package-ubuntu-deb.yaml ├── favicon.ico ├── src ├── default-stylesheet.h ├── draw_text_font.h ├── pixelflood.h ├── audio.cpp ├── instance.cpp ├── error.h ├── webservices.h ├── filter-plugins │ ├── cairo.h │ ├── template.c │ ├── demo.c │ ├── demo2.cpp │ ├── cairo.cpp │ ├── README │ ├── keep-alive.cpp │ ├── demoocv2.cpp │ └── demoocv.cpp ├── http_server_rest.h ├── feed_exec.h ├── icons.h ├── instance.h ├── failure.h ├── audio_ffmpeg.h ├── encoding.h ├── http_client.h ├── resize_fine.h ├── audio.h ├── draw.h ├── http_utils.h ├── http_auth.h ├── http_auth_pam.h ├── exec.h ├── filter_boost_contrast.h ├── filter_mirror_h.h ├── filter_mirror_v.h ├── schedule.h ├── http_content_theora.h ├── selection_mask.h ├── filter_noise_neighavg.h ├── resize_crop.h ├── source-plugins │ ├── README │ ├── Makefile │ └── demo.cpp ├── gui_sdl.h ├── filter_despeckle.h ├── source_black.h ├── feed_mqtt.h ├── ptz_v4l.h ├── filter_overlay.h ├── filter_median.h ├── pos.h ├── filter_average.h ├── filter_draw.h ├── streamwriter-plugins │ ├── Makefile │ └── demo.c ├── feed.cpp ├── filter_chromakey.h ├── source_static.h ├── target_vnc.h ├── filter_apply_mask.h ├── meta-plugins │ └── Makefile ├── filter_copy.h ├── filter_grayscale.h ├── gui.h ├── filter_mirror_v.cpp ├── gui.cpp ├── filter_add_bitmap.h ├── cleaner.h ├── http_cookies.h ├── audio_alsa.h ├── feed.h ├── view_html_all.h ├── resize.h ├── target_gstreamer.h ├── filter_anigif_overlay.h ├── filter_motion_only.h ├── log.h ├── ptz.cpp ├── source_filesystem_jpeg.h ├── source_ffmpeg.h ├── filter_mirror_h.cpp ├── source_gstreamer.h ├── ptz.h ├── target_jpeg.h ├── source_http_mjpeg.h ├── source_http_bmp.h ├── source_http_png.h ├── view_html_grid.h ├── source_http_jpeg.h ├── motion_trigger_other_source.h ├── v4l2_loopback.h ├── controls.h ├── announce_upnp.h ├── view_all.h ├── controls_software.h ├── audio_trigger.h ├── target_extpipe.h ├── filter_overlay_on_motion.h ├── controls.cpp ├── http_server_support.h ├── source_pixelflood.h ├── target_ffmpeg.h ├── target_new_source.h ├── gen.h ├── view_pip.h ├── filter.h ├── error.cpp ├── controls_v4l.h ├── filter_add_text.h ├── source_delay.h ├── source_plugin.h ├── view_3d.h ├── filter_add_scaled_text.h ├── source_other.h ├── source_black.cpp ├── target_gwavi.h ├── target_pixelflood.h ├── filter_noise_neighavg.cpp ├── filter_draw.cpp ├── filter_boost_contrast.cpp ├── filter_average.cpp ├── list-libcamera.cpp ├── view_ss.h ├── target_pipewire.h ├── target_avi.h ├── filter_add_bitmap.cpp ├── http_auth.cpp ├── draw.cpp ├── filter_median.cpp ├── feed_exec.cpp ├── filter_copy.cpp ├── filter_apply_mask.cpp ├── filter_plugin.h ├── motion_trigger.h ├── ws_server_tls.h ├── source_pipewire.h ├── stats_tracker.h ├── view.h ├── source_v4l.h ├── filter_plugin_frei0r.h ├── filter_marker_simple.h ├── picio.h ├── motiontrigger-plugins │ ├── demo.cpp │ ├── README │ ├── hue-only.cpp │ ├── demoocv2.cpp │ ├── Makefile │ └── network.cpp ├── view_html_all.cpp ├── filter_chromakey.cpp ├── http_auth_pam.cpp ├── target_plugin.h ├── filter_add_scaled_text.cpp ├── filter_plugin.cpp ├── view.cpp ├── source_static.cpp ├── filter_scroll.h ├── cleaner.cpp ├── ws_server.h ├── filter_grayscale.cpp ├── filter_overlay.cpp ├── selection_mask.cpp ├── filter_overlay_on_motion.cpp ├── target.h ├── motion_trigger_generic.h ├── source_libcamera.h ├── video_frame.h ├── meta.h ├── source_plugin.cpp ├── filter.cpp ├── resize_crop.cpp ├── http_cookies.cpp └── filter_motion_only.cpp ├── examples ├── overlay-test.png ├── pipewire-target.cfg ├── video4linux.cfg ├── mjpeg-multiplexer.cfg ├── multicast-tx.cfg ├── pipewire-source.cfg ├── libcamera.cfg ├── pixelflood.cfg ├── browser.cfg ├── crop.cfg ├── lcdproc-overlay.cfg ├── interfacing-to-obs-studio.cfg ├── lcdproc-overlay.py ├── timelapse.cfg ├── overlay-on-motion.cfg └── mosaic-stream.cfg ├── contrib └── systemd-setup │ └── constatus.service ├── man └── constatus.1 ├── Makefile ├── LICENSE └── .lgtm.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so.* 4 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh $@ 4 | -------------------------------------------------------------------------------- /debian/upstream/metadata: -------------------------------------------------------------------------------- 1 | Repository: https://github.com/flok99/constatus 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [folkertvanheusden] 2 | patreon: folkertvanheusden 3 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/folkertvanheusden/constatus/HEAD/favicon.ico -------------------------------------------------------------------------------- /src/default-stylesheet.h: -------------------------------------------------------------------------------- 1 | extern unsigned char sc_css[]; 2 | extern unsigned int sc_css_len; 3 | -------------------------------------------------------------------------------- /examples/overlay-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/folkertvanheusden/constatus/HEAD/examples/overlay-test.png -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | constatus (6.0-0) unstable; urgency=low 2 | 3 | * New upstream release. 4 | 5 | -- Folkert van Heusden Sun, 11 Jun 2023 10:18:00 +0200 6 | -------------------------------------------------------------------------------- /src/draw_text_font.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | extern unsigned int cruft_ttf_len; 4 | extern unsigned char cruft_ttf[]; 5 | -------------------------------------------------------------------------------- /src/pixelflood.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | typedef enum { PP_TCP_TXT, PP_UDP_BIN, PP_UDP_TXT } pixelflood_protocol_t; 5 | -------------------------------------------------------------------------------- /src/audio.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | 3 | #include "audio.h" 4 | 5 | audio::audio() 6 | { 7 | } 8 | 9 | audio::~audio() 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /src/instance.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | 3 | #include "instance.h" 4 | 5 | instance::instance() 6 | { 7 | } 8 | 9 | instance::~instance() 10 | { 11 | } 12 | -------------------------------------------------------------------------------- /src/error.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | void error_exit(const bool se, const char *format, ...) __attribute__ ((__noreturn__)); 4 | void cpt(const int err); 5 | -------------------------------------------------------------------------------- /src/webservices.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | typedef struct 6 | { 7 | std::string key_file, certificate_file; 8 | } ssl_pars_t; 9 | -------------------------------------------------------------------------------- /src/filter-plugins/cairo.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | cairo_surface_t * rgb_to_cairo(const uint8_t *const in, const int w, const int h, uint32_t **temp); 5 | void cairo_to_rgb(cairo_surface_t *const cs, const int w, const int h, uint8_t *out); 6 | -------------------------------------------------------------------------------- /src/http_server_rest.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "http_server.h" 4 | 5 | void run_rest(h_handle_t & hh, configuration_t *const cfg, const std::string & path, const std::map & pars, const std::string & snapshot_dir, const int quality); 6 | -------------------------------------------------------------------------------- /.github/workflows/package-debian-deb.yaml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | jobs: 4 | build-debs: 5 | runs-on: debian-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - name: Build Debian packages 9 | uses: jtdor/build-deb-action@v1.7.0 10 | with: 11 | buildpackage-opts: --build=binary --no-sign 12 | -------------------------------------------------------------------------------- /.github/workflows/package-ubuntu-deb.yaml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | jobs: 4 | build-debs: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - name: Build Ubuntu packages 9 | uses: jtdor/build-deb-action@v1.7.0 10 | with: 11 | buildpackage-opts: --build=binary --no-sign 12 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: constatus 3 | Upstream-Contact: Folkert van Heusden 4 | Source: https://vanheusden.com/constatus/ 5 | 6 | Files: * 7 | Copyright: 2017-2023 Folkert van Heusden 8 | License: MIT License 9 | -------------------------------------------------------------------------------- /src/feed_exec.h: -------------------------------------------------------------------------------- 1 | #include "feed.h" 2 | 3 | 4 | class feed_exec : public feed 5 | { 6 | private: 7 | const std::string commandline; 8 | const int interval_ms; 9 | 10 | public: 11 | feed_exec(const std::string & commandline, const int interval_ms); 12 | virtual ~feed_exec(); 13 | 14 | void operator()() override; 15 | }; 16 | -------------------------------------------------------------------------------- /src/icons.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | extern const unsigned char favicon_ico[5694]; 5 | extern const unsigned char play_svg[185]; 6 | extern const unsigned char stop_svg[136]; 7 | extern const unsigned char pause_svg[188]; 8 | extern const unsigned char fierman_icon_jpg[1472]; 9 | -------------------------------------------------------------------------------- /src/instance.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | class interface; 7 | 8 | class instance 9 | { 10 | public: 11 | instance(); 12 | virtual ~instance(); 13 | 14 | std::vector interfaces; 15 | std::string name, descr; 16 | }; 17 | -------------------------------------------------------------------------------- /src/failure.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include "pos.h" 6 | 7 | typedef enum { F_MESSAGE, F_SIMPLE, F_NOTHING } failure_mode_t; 8 | 9 | typedef struct { 10 | failure_mode_t fm; 11 | std::string bg_bitmap, message; 12 | pos_t position; 13 | } failure_t; 14 | -------------------------------------------------------------------------------- /src/audio_ffmpeg.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include "audio.h" 5 | 6 | class audio_ffmpeg : public audio 7 | { 8 | public: 9 | audio_ffmpeg(); 10 | ~audio_ffmpeg(); 11 | 12 | void put_audio(const int16_t *samples, const size_t n_samples); 13 | 14 | void operator()() override; 15 | }; 16 | -------------------------------------------------------------------------------- /src/encoding.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | typedef enum { E_RGB, E_BGR, E_JPEG, E_YUYV } encoding_t; 5 | 6 | void yuy2_to_rgb(const uint8_t *const in, const int width, const int height, uint8_t **out); 7 | void rgb_to_yuy2(const uint8_t *const in, const int width, const int height, uint8_t **const out); 8 | -------------------------------------------------------------------------------- /src/http_client.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | bool http_get(const std::string & url, const bool ignore_cert, const char *const auth, const bool verbose, uint8_t **const out, size_t *const out_n, std::atomic_bool *const stop_flag); 9 | -------------------------------------------------------------------------------- /src/resize_fine.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | #include "resize.h" 6 | 7 | class resize_fine : public resize 8 | { 9 | public: 10 | resize_fine(); 11 | virtual ~resize_fine(); 12 | 13 | void do_resize(const int win, const int hin, const uint8_t *const in, const int wout, const int hout, uint8_t **out) override; 14 | }; 15 | -------------------------------------------------------------------------------- /src/audio.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class audio 9 | { 10 | public: 11 | audio(); 12 | virtual ~audio(); 13 | 14 | virtual int get_samplerate() = 0; 15 | 16 | virtual std::tuple get_audio_mono(const size_t n_samples) = 0; 17 | 18 | virtual void operator()() = 0; 19 | }; 20 | -------------------------------------------------------------------------------- /src/draw.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | void draw_horizonal(uint8_t *const target, const int tw, const int x, const int y, const int w, const rgb_t col); 4 | void draw_vertical(uint8_t *const target, const int tw, const int x, const int y, const int h, const rgb_t col); 5 | void draw_box(uint8_t *const target, const int tw, const int x1, const int y1, const int x2, const int y2, const rgb_t col); 6 | -------------------------------------------------------------------------------- /src/http_utils.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | 5 | #if HAVE_OPENSSL == 1 6 | SSL_CTX *create_context(const ssl_pars_t & sp); 7 | #endif 8 | void CLOSE_SSL(h_handle_t & hh); 9 | int AVAILABLE_SSL(h_handle_t & hh); 10 | int READ_SSL(h_handle_t & hh, char *whereto, int len); 11 | int WRITE_SSL(h_handle_t & hh, const char *wherefrom, int len); 12 | void ACCEPT_SSL(h_handle_t & hh); 13 | -------------------------------------------------------------------------------- /src/http_auth.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | class http_auth { 8 | private: 9 | const std::string auth_file; 10 | 11 | protected: 12 | http_auth() { } 13 | 14 | public: 15 | http_auth(const std::string & auth_file); 16 | virtual ~http_auth(); 17 | 18 | virtual std::tuple authenticate(const std::string & username, const std::string & password); 19 | }; 20 | -------------------------------------------------------------------------------- /src/http_auth_pam.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_LIBPAM == 1 5 | #include 6 | #include 7 | 8 | #include "http_auth.h" 9 | 10 | class http_auth_pam : public http_auth 11 | { 12 | public: 13 | http_auth_pam(); 14 | virtual ~http_auth_pam(); 15 | 16 | std::tuple authenticate(const std::string & username, const std::string & password) override; 17 | }; 18 | #endif 19 | -------------------------------------------------------------------------------- /src/exec.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | bool check_thread(std::thread **const handle); 7 | std::thread * exec(const std::string & what, const std::string & parameter); 8 | FILE * exec(const std::string & command_line); 9 | 10 | void exec_with_pty(const std::string & command, int *const fd, pid_t *const pid); 11 | 12 | void fire_and_forget(const std::string & command, const std::string & argument); 13 | -------------------------------------------------------------------------------- /src/filter_boost_contrast.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | class filter_boost_contrast : public filter 6 | { 7 | public: 8 | filter_boost_contrast(); 9 | ~filter_boost_contrast(); 10 | 11 | bool uses_in_out() const override { return false; } 12 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 13 | }; 14 | -------------------------------------------------------------------------------- /src/filter_mirror_h.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | class filter_mirror_h : public filter 6 | { 7 | public: 8 | filter_mirror_h(); 9 | ~filter_mirror_h(); 10 | 11 | bool uses_in_out() const override { return true; } 12 | void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 13 | }; 14 | -------------------------------------------------------------------------------- /src/filter_mirror_v.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | class filter_mirror_v : public filter 6 | { 7 | public: 8 | filter_mirror_v(); 9 | ~filter_mirror_v(); 10 | 11 | bool uses_in_out() const override { return true; } 12 | void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 13 | }; 14 | -------------------------------------------------------------------------------- /src/schedule.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct 9 | { 10 | uint8_t day_of_week; 11 | uint32_t start, end; // in seconds 12 | bool state; 13 | } part_of_day; 14 | 15 | class schedule 16 | { 17 | private: 18 | std::vector s; 19 | 20 | public: 21 | schedule(const std::vector & sched); 22 | ~schedule(); 23 | 24 | bool is_on(); 25 | }; 26 | -------------------------------------------------------------------------------- /src/http_content_theora.h: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #if HAVE_THEORA == 1 4 | #include 5 | 6 | typedef struct { 7 | ogg_stream_state ss; 8 | th_enc_ctx *ctx; 9 | th_info ti; 10 | } theora_t; 11 | 12 | theora_t *theora_init(const int w, const int h, const int fps, const int quality, h_handle_t & hh); 13 | void theora_uninit(theora_t *t); 14 | 15 | int theora_write_frame(theora_t *const t, h_handle_t & hh, int w, int h, uint8_t *yuv_y, uint8_t *yuv_u, uint8_t *yuv_v, int last); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/selection_mask.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | class resize; 8 | 9 | class selection_mask 10 | { 11 | private: 12 | resize *const r; 13 | 14 | uint8_t *pixels; 15 | int w, h; 16 | 17 | uint8_t *cache; 18 | int cw, ch; 19 | 20 | public: 21 | selection_mask(resize *const r, const std::string & file); 22 | virtual ~selection_mask(); 23 | 24 | uint8_t *get_mask(const int rw, const int rh); 25 | }; 26 | -------------------------------------------------------------------------------- /examples/pipewire-target.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "debug"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "video source"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 640; 15 | height = 480; 16 | } 17 | 18 | targets = ( 19 | { 20 | id = "1-2"; 21 | descr = "send to pipewire server"; 22 | handle-failure = true; 23 | fps = 15.0; 24 | format = "pipewire"; 25 | } 26 | ) 27 | }) 28 | -------------------------------------------------------------------------------- /src/filter_noise_neighavg.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | class filter_noise_neighavg : public filter 6 | { 7 | public: 8 | filter_noise_neighavg(); 9 | virtual ~filter_noise_neighavg(); 10 | 11 | bool uses_in_out() const override { return true; } 12 | void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 13 | }; 14 | -------------------------------------------------------------------------------- /src/resize_crop.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "resize.h" 8 | 9 | class resize_crop : public resize 10 | { 11 | private: 12 | const bool resize_crop_center, fill_max; 13 | 14 | public: 15 | resize_crop(const bool resize_crop_center, const bool fill_max); 16 | virtual ~resize_crop(); 17 | 18 | void do_resize(const int win, const int hin, const uint8_t *const in, const int wout, const int hout, uint8_t **out) override; 19 | }; 20 | -------------------------------------------------------------------------------- /src/source-plugins/README: -------------------------------------------------------------------------------- 1 | DEMO 2 | ==== 3 | demo.cpp is a wandering pixel 4 | 5 | 6 | VNC CLIENT 7 | ========== 8 | vnc.cpp is a VNC client. 9 | As parameters it requires 'ip-address port-number password' (where password is optional if the VNC server is not requesting it). 10 | 11 | 12 | configuration example 13 | --------------------- 14 | descr = "my plugin source"; 15 | type = "plugin"; 16 | width = 1920; 17 | height = 1080; 18 | source-plugin-file = "source-plugins/vnc.so.0.1"; 19 | source-plugin-parameter = "192.168.1.100 5901 mypassword"; 20 | 21 | -------------------------------------------------------------------------------- /src/gui_sdl.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_LIBSDL2 == 1 5 | #include 6 | 7 | #include "gui.h" 8 | 9 | class gui_sdl : public gui 10 | { 11 | public: 12 | gui_sdl(configuration_t *const cfg, const std::string & id, const std::string & descr, source *const s, const double fps, const int w, const int h, std::vector *const filters, const bool handle_failure); 13 | virtual ~gui_sdl(); 14 | 15 | virtual void operator()() override; 16 | }; 17 | #endif 18 | -------------------------------------------------------------------------------- /src/filter_despeckle.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | class filter_despeckle : public filter 6 | { 7 | private: 8 | const std::string pattern; 9 | 10 | public: 11 | filter_despeckle(const std::string & pattern); 12 | ~filter_despeckle(); 13 | 14 | bool uses_in_out() const override { return true; } 15 | void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 16 | }; 17 | -------------------------------------------------------------------------------- /src/source_black.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_black : public source 10 | { 11 | public: 12 | source_black(const std::string & id, const std::string & descr, const int width, const int height, controls *const c, const std::map & text_feeds); 13 | ~source_black(); 14 | 15 | virtual video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 16 | 17 | void operator()() override; 18 | }; 19 | -------------------------------------------------------------------------------- /src/feed_mqtt.h: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #if HAVE_LIBMOSQUITTO == 1 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "feed.h" 9 | 10 | 11 | class feed_mqtt : public feed 12 | { 13 | private: 14 | const std::vector topics; 15 | struct mosquitto *mqtt { nullptr }; 16 | 17 | public: 18 | feed_mqtt(const std::string & host, const int port, const std::vector & topics); 19 | virtual ~feed_mqtt(); 20 | 21 | void set_text(const std::string & text); 22 | void subscribe_topics(); 23 | 24 | void operator()() override; 25 | }; 26 | #endif 27 | -------------------------------------------------------------------------------- /src/ptz_v4l.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include "ptz.h" 5 | 6 | class ptz_v4l : public ptz 7 | { 8 | private: 9 | const int fd; 10 | 11 | ptz_v4l(const int fd); 12 | 13 | bool pan_relative(const double angle); 14 | bool tilt_relative(const double angle); 15 | bool pan_absolute(const double angle); 16 | bool tilt_absolute(const double angle); 17 | 18 | public: 19 | virtual ~ptz_v4l(); 20 | 21 | static ptz_v4l * check_is_supported(const int fd); 22 | 23 | void reset_to_center(); 24 | 25 | virtual void operator()(); 26 | }; 27 | -------------------------------------------------------------------------------- /src/filter_overlay.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | #include "filter.h" 6 | 7 | class filter_overlay : public filter 8 | { 9 | const pos_t pos; 10 | int w, h; 11 | uint8_t *pixels; 12 | 13 | public: 14 | filter_overlay(const std::string & file, const pos_t & pos); 15 | ~filter_overlay(); 16 | 17 | bool uses_in_out() const override { return false; } 18 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 19 | }; 20 | -------------------------------------------------------------------------------- /src/filter_median.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class filter_median : public filter 9 | { 10 | private: 11 | const size_t median_n; 12 | std::vector h_frames; 13 | 14 | public: 15 | filter_median(const size_t median_n); 16 | virtual ~filter_median(); 17 | 18 | bool uses_in_out() const override { return false; } 19 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/pos.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | 6 | typedef enum 7 | { 8 | none, 9 | upper_left, 10 | upper_center, 11 | upper_right, 12 | center_left, 13 | center_center, 14 | center_right, 15 | lower_left, 16 | lower_center, 17 | lower_right, 18 | xy, 19 | axy 20 | } pos_type_t; 21 | 22 | typedef struct { 23 | pos_type_t type; 24 | int x, y; 25 | } pos_t; 26 | 27 | pos_t pos_to_pos(const std::string & s_position); 28 | std::tuple pos_to_xy(const pos_t & pos, const int win, const int hin, const int tgt_w, const int tgt_h); 29 | -------------------------------------------------------------------------------- /src/filter_average.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class filter_average : public filter 9 | { 10 | private: 11 | const size_t average_n; 12 | std::vector h_frames; 13 | 14 | public: 15 | filter_average(const size_t average_n); 16 | virtual ~filter_average(); 17 | 18 | bool uses_in_out() const override { return false; } 19 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/filter_draw.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | #include "filter.h" 6 | 7 | class filter_draw : public filter 8 | { 9 | protected: 10 | const int x, y, w, h; 11 | const rgb_t col; 12 | 13 | public: 14 | filter_draw(const int x, const int y, const int w, const int h, const rgb_t col); 15 | ~filter_draw(); 16 | 17 | bool uses_in_out() const override { return false; } 18 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 19 | }; 20 | -------------------------------------------------------------------------------- /src/streamwriter-plugins/Makefile: -------------------------------------------------------------------------------- 1 | # (C) 2017 by folkert van heusden, this file is released in the public domain 2 | INSTALL_PREFIX=/usr/local 3 | 4 | CFLAGS=-fPIC -Wall -pedantic -ggdb3 5 | CXXFLAGS=-fPIC -Wall -pedantic -ggdb3 6 | VERSION=0.1 7 | 8 | OBJS1=demo.o 9 | 10 | all: lib1 11 | 12 | lib1: $(OBJS1) 13 | ar -r demo.a $(OBJS1) 14 | ld -g -x -lm -shared -soname demo.so.2 -o demo.so.$(VERSION) --whole-archive demo.a 15 | 16 | install: all 17 | cp demo.so.* $(INSTALL_PREFIX)/lib 18 | /sbin/ldconfig 19 | 20 | uninstall: clean 21 | rm -f $(INSTALL_PREFIX)/lib/demo.so.* 22 | 23 | clean: 24 | rm -f $(OBJS1) demo.a demo.so.* core 25 | -------------------------------------------------------------------------------- /src/feed.cpp: -------------------------------------------------------------------------------- 1 | #include "feed.h" 2 | #include "utils.h" 3 | 4 | 5 | feed::feed() 6 | { 7 | } 8 | 9 | feed::~feed() 10 | { 11 | } 12 | 13 | std::optional > feed::wait_for_text(const uint64_t after, const uint64_t to) 14 | { 15 | std::unique_lock lck(lock); 16 | 17 | uint64_t stop_at = get_us() + to; 18 | 19 | while(latest_ts <= after || latest_ts == 0) { 20 | int64_t time_left = stop_at - get_us(); 21 | 22 | if (time_left <= 0 || cond.wait_for(lck, std::chrono::microseconds(to)) == std::cv_status::timeout) 23 | return { }; 24 | } 25 | 26 | return { { latest_text, latest_ts } }; 27 | } 28 | -------------------------------------------------------------------------------- /src/filter_chromakey.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | #include "filter.h" 6 | 7 | class resize; 8 | 9 | class filter_chromakey : public filter 10 | { 11 | protected: 12 | source *const cks; 13 | resize *const r; 14 | 15 | public: 16 | filter_chromakey(source *const cks, resize *const r); 17 | ~filter_chromakey(); 18 | 19 | bool uses_in_out() const override { return false; } 20 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 21 | }; 22 | -------------------------------------------------------------------------------- /src/source_static.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_static : public source 10 | { 11 | public: 12 | source_static(const std::string & id, const std::string & descr, const int width, const int height, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 13 | ~source_static(); 14 | 15 | virtual video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 16 | 17 | void operator()() override; 18 | }; 19 | -------------------------------------------------------------------------------- /src/target_vnc.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | 5 | class target_vnc : public target 6 | { 7 | private: 8 | int fd; 9 | 10 | public: 11 | target_vnc(const std::string & id, const std::string & descr, source *const s, const listen_adapter_t & la, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_end, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 12 | virtual ~target_vnc(); 13 | 14 | void operator()() override; 15 | }; 16 | -------------------------------------------------------------------------------- /contrib/systemd-setup/constatus.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description = constatus 3 | 4 | ## Use the following to ensure constatus starts after the network is up. 5 | After = network.target 6 | 7 | [Service] 8 | Type=simple 9 | 10 | # A globally-writable directory 11 | WorkingDirectory = /tmp 12 | 13 | ExecStart = /usr/local/bin/constatus -c /etc/constatus/constatus.cfg -S 14 | 15 | # Send STDOUT/STDERR to journal, view it with "journalctl" 16 | StandardOutput = journal 17 | StandardError = inherit 18 | 19 | ## Optional: run as specific user (otherwise will run as root). 20 | #User=www-data 21 | #Group=www-data 22 | 23 | [Install] 24 | WantedBy = multi-user.target 25 | -------------------------------------------------------------------------------- /src/filter_apply_mask.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | class selection_mask; 6 | 7 | class filter_apply_mask : public filter 8 | { 9 | private: 10 | selection_mask *const psb; 11 | const bool soft_mask; 12 | 13 | public: 14 | filter_apply_mask(selection_mask *const pixel_select_bitmap, const bool soft_mask); 15 | ~filter_apply_mask(); 16 | 17 | bool uses_in_out() const override { return false; } 18 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 19 | }; 20 | -------------------------------------------------------------------------------- /src/meta-plugins/Makefile: -------------------------------------------------------------------------------- 1 | # (C) 2017 by folkert van heusden, this file is released in the public domain 2 | INSTALL_PREFIX=/usr/local 3 | 4 | LDFLAGS=`pkg-config --libs libgps` 5 | CXXFLAGS=-fPIC -Wall -pedantic -ggdb3 `pkg-config --cflags libgps` -std=c++11 6 | VERSION=0.1 7 | 8 | OBJS1=gps.o 9 | 10 | all: gps 11 | 12 | gps: $(OBJS1) 13 | ar -r gps.a $(OBJS1) 14 | ld -g -x -lm $(LDFLAGS) -shared -soname gps.so.1 -o gps.so.$(VERSION) --whole-archive gps.a 15 | 16 | install: all 17 | cp gps.so.* $(INSTALL_PREFIX)/lib 18 | /sbin/ldconfig 19 | 20 | uninstall: clean 21 | rm -f $(INSTALL_PREFIX)/lib/gps.so.* 22 | 23 | clean: 24 | rm -f $(OBJS1) gps.a gps.so.* core 25 | -------------------------------------------------------------------------------- /src/filter_copy.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class filter_copy : public filter 9 | { 10 | private: 11 | const std::string remember_as; 12 | const int x, y, w, h; 13 | 14 | public: 15 | filter_copy(const std::string & remember_as, const int x, const int y, const int w, const int h); 16 | virtual ~filter_copy(); 17 | 18 | bool uses_in_out() const override { return false; } 19 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/filter_grayscale.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "filter.h" 4 | 5 | typedef enum { G_FAST, G_CIE_1931, G_PAL_NTSC, G_LIGHTNESS } to_grayscale_t; 6 | 7 | class filter_grayscale : public filter 8 | { 9 | private: 10 | const to_grayscale_t mode; 11 | 12 | public: 13 | filter_grayscale(const to_grayscale_t mode); 14 | ~filter_grayscale(); 15 | 16 | bool uses_in_out() const override { return true; } 17 | void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 18 | }; 19 | -------------------------------------------------------------------------------- /src/gui.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "cfg.h" 4 | #include "interface.h" 5 | 6 | class gui : public interface 7 | { 8 | protected: 9 | configuration_t *const cfg; 10 | source *const s; 11 | const double fps; 12 | const int w, h; 13 | std::vector *const filters; 14 | const bool handle_failure; 15 | 16 | public: 17 | gui(configuration_t *const cfg, const std::string & id, const std::string & descr, source *const s, const double fps, const int w, const int h, std::vector *const filters, const bool handle_failure); 18 | 19 | virtual ~gui(); 20 | 21 | virtual void operator()(); 22 | }; 23 | -------------------------------------------------------------------------------- /src/filter_mirror_v.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | 6 | #include "gen.h" 7 | #include "filter_mirror_v.h" 8 | 9 | filter_mirror_v::filter_mirror_v() 10 | { 11 | } 12 | 13 | filter_mirror_v::~filter_mirror_v() 14 | { 15 | } 16 | 17 | void filter_mirror_v::apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) 18 | { 19 | const size_t bytes = w * 3; 20 | 21 | for(int y=0; y *const filters, const bool handle_failure) : interface(id, descr), cfg(cfg), s(s), fps(fps), w(w), h(h), filters(filters), handle_failure(handle_failure) 9 | { 10 | local_stop_flag = false; 11 | ct = CT_GUI; 12 | } 13 | 14 | gui::~gui() 15 | { 16 | free_filters(filters); 17 | } 18 | 19 | void gui::operator()() 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /src/filter_add_bitmap.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class interface; 9 | 10 | class filter_add_bitmap : public filter 11 | { 12 | private: 13 | const std::string which; 14 | const int x, y; 15 | 16 | public: 17 | filter_add_bitmap(const std::string & which, const int x, const int y); 18 | ~filter_add_bitmap(); 19 | 20 | bool uses_in_out() const override { return false; } 21 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 22 | }; 23 | -------------------------------------------------------------------------------- /src/cleaner.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "interface.h" 8 | 9 | class db; 10 | 11 | class cleaner : public interface 12 | { 13 | private: 14 | std::thread *th; 15 | std::atomic_bool local_stop_flag; 16 | db *dbi; 17 | const int check_interval, purge_interval, cookies_max_age; 18 | 19 | public: 20 | cleaner(const std::string & db_url, const std::string & db_user, const std::string & dp_pass, const int check_interval, const int purge_interval, const int cookies_max_age); 21 | virtual ~cleaner(); 22 | 23 | void start() override; 24 | 25 | void operator()() override; 26 | }; 27 | -------------------------------------------------------------------------------- /src/http_cookies.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class http_cookies 9 | { 10 | private: 11 | std::mutex lock; 12 | std::map > cookies; 13 | 14 | public: 15 | http_cookies(); 16 | virtual ~http_cookies(); 17 | 18 | void clean_cookies(const int max_age); 19 | std::string get_cookie(const std::string & user); 20 | std::string get_cookie_user(const std::string & cookie_key); 21 | void update_cookie(const std::string & user, const std::string & key); 22 | void delete_cookie_for_user(const std::string & user); 23 | }; 24 | -------------------------------------------------------------------------------- /src/filter-plugins/template.c: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | 4 | void * init_filter(const char *const parameter) 5 | { 6 | // you can use the parameter for anything you want 7 | // e.g. the filename of a configuration file or 8 | // maybe a variable or whatever 9 | 10 | // what you return here, will be given as a parameter 11 | // to apply_filter 12 | 13 | return NULL; 14 | } 15 | 16 | void apply_filter(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result) 17 | { 18 | } 19 | 20 | void uninit_filter(void *arg) 21 | { 22 | // free memory etc 23 | } 24 | -------------------------------------------------------------------------------- /src/audio_alsa.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if ALSA_FOUND == 1 5 | 6 | #include 7 | #include 8 | 9 | #include "audio.h" 10 | 11 | class audio_alsa : public audio 12 | { 13 | private: 14 | const std::string dev_name; 15 | int sample_rate, n_channels; 16 | 17 | snd_pcm_t *pcm_handle; 18 | 19 | public: 20 | audio_alsa(const std::string & dev_name, const int sample_rate); 21 | ~audio_alsa(); 22 | 23 | int get_samplerate() override { return sample_rate; } 24 | 25 | std::tuple get_audio_mono(const size_t n_samples) override; 26 | 27 | void operator()() override { } 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/feed.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | class feed 12 | { 13 | protected: 14 | std::atomic_bool stop_flag { false }; 15 | std::thread *th { nullptr }; 16 | std::condition_variable cond; 17 | mutable std::mutex lock; 18 | std::string latest_text; 19 | uint64_t latest_ts { 0 }; 20 | 21 | public: 22 | feed(); 23 | virtual ~feed(); 24 | 25 | std::optional > wait_for_text(const uint64_t after, const uint64_t to); 26 | 27 | virtual void operator()() = 0; 28 | }; 29 | -------------------------------------------------------------------------------- /src/view_html_all.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cfg.h" 8 | #include "view.h" 9 | 10 | class view_html_all : public view 11 | { 12 | private: 13 | virtual video_frame * get_frame(const bool handle_failure, const uint64_t after) override { return { }; } 14 | 15 | public: 16 | view_html_all(configuration_t *const cfg, const std::string & id, const std::string & descr, const std::vector & sources, const int jpeg_quality); 17 | virtual ~view_html_all(); 18 | 19 | std::string get_html(const std::map & pars) const override; 20 | 21 | void operator()() override; 22 | }; 23 | -------------------------------------------------------------------------------- /man/constatus.1: -------------------------------------------------------------------------------- 1 | .TH constatus 1 "2017-09-10" "constatus" "User Commands" 2 | .SH NAME 3 | constatus \- Records a videofile when motion is detected via a camera. 4 | .SH SYNOPSIS 5 | \fBconstatus\fP [options] 6 | .SH DESCRIPTION 7 | \fBconstatus records a videofile when motion is detected via a camera. 8 | Constatus supports locally attached camera's or network cameras via MJPEG/RTSP. 9 | .SH OPTIONS 10 | .PP 11 | .IP "\fB\-c\fR \fR\fIconfig\fR" 12 | Specify a path to the config file to use. 13 | .IP "\fB\-f\fR" 14 | Fork into the background 15 | .IP "\fB\-p\fR \fR\fIpidfile\fR" 16 | Specify a pidfile to write PID to. 17 | .IP "\fB\-v\fR" 18 | Enable verbose mode. 19 | .IP "\fB\-V\fR" 20 | Display version information. 21 | .IP "\fB\-h\fR" 22 | Display help message. 23 | -------------------------------------------------------------------------------- /src/resize.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "gen.h" 7 | #include "pos.h" 8 | 9 | class resize 10 | { 11 | public: 12 | resize(); 13 | virtual ~resize(); 14 | 15 | virtual void do_resize(const int win, const int hin, const uint8_t *const in, const int wout, const int hout, uint8_t **out); 16 | }; 17 | 18 | void picture_in_picture(resize *const r, uint8_t *const tgt, const int tgt_w, const int tgt_h, const uint8_t *const in, const int win, const int hin, const int perc, const pos_t pos); 19 | void picture_in_picture(uint8_t *const tgt, const int tgt_w, const int tgt_h, const uint8_t *const in, const int win, const int hin, const pos_t pos); 20 | -------------------------------------------------------------------------------- /src/target_gstreamer.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | 5 | #if HAVE_GSTREAMER == 1 6 | #include 7 | #include 8 | 9 | class target_gstreamer : public target 10 | { 11 | private: 12 | const std::string pipeline; 13 | 14 | void put_frame(GstAppSrc *const appsrc, const uint8_t *const work, const size_t n); 15 | 16 | public: 17 | target_gstreamer(const std::string & id, const std::string & descr, source *const s, const std::string & pipeline, const double interval, const std::vector *const filters, configuration_t *const cfg, schedule *const sched); 18 | virtual ~target_gstreamer(); 19 | 20 | void operator()() override; 21 | }; 22 | #endif 23 | -------------------------------------------------------------------------------- /src/filter_anigif_overlay.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #if HAVE_IMAGICK == 1 6 | #include 7 | 8 | #include "filter.h" 9 | 10 | class filter_anigif_overlay : public filter 11 | { 12 | private: 13 | const pos_t pos; 14 | std::vector imageList; 15 | size_t cur_page { 0 }; 16 | 17 | public: 18 | filter_anigif_overlay(const std::string & file, const pos_t & pos); 19 | ~filter_anigif_overlay(); 20 | 21 | bool uses_in_out() const override { return false; } 22 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 23 | }; 24 | #endif 25 | -------------------------------------------------------------------------------- /src/filter_motion_only.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class selection_mask; 9 | 10 | class filter_motion_only : public filter 11 | { 12 | private: 13 | selection_mask *const pixel_select_bitmap; 14 | uint8_t *prev1, *prev2; 15 | const int noise_level; 16 | const bool diff_value; 17 | 18 | public: 19 | filter_motion_only(selection_mask *const pixel_select_bitmap, const int noise_level, const bool diff_value); 20 | virtual ~filter_motion_only(); 21 | 22 | bool uses_in_out() const override { return false; } 23 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 24 | }; 25 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #define LL_FATAL 0 7 | #define LL_ERR 1 8 | #define LL_WARNING 2 9 | #define LL_INFO 3 10 | #define LL_DEBUG 4 11 | #define LL_DEBUG_VERBOSE 5 12 | 13 | std::string ll_to_str(const int ll); 14 | int get_default_loglevel(); 15 | void setlogfile(const char *const other, const int loglevel); 16 | void log(const int loglevel, const char *const what, ...); 17 | void lognee(const int loglevel, const char *const what, ...); 18 | void log(const std::string & id, const int loglevel, const char *const what, ...); 19 | void log(const int loglevel, const std::string & what, ...); 20 | int curl_log(CURL *handle, curl_infotype type, char *data, size_t size, void *userp); 21 | -------------------------------------------------------------------------------- /src/ptz.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "log.h" 3 | #include "ptz.h" 4 | #include "ptz_v4l.h" 5 | 6 | ptz::ptz() : interface("ptz", "") 7 | { 8 | } 9 | 10 | ptz::~ptz() 11 | { 12 | } 13 | 14 | ptz * ptz::check_is_supported(const int fd) 15 | { 16 | ptz *rc = nullptr; 17 | 18 | rc = ptz_v4l::check_is_supported(fd); 19 | if (rc) 20 | return rc; 21 | 22 | log(LL_INFO, "No PTZ controls"); 23 | 24 | return nullptr; 25 | } 26 | 27 | void ptz::pan(const double abs_angle) 28 | { 29 | if (!pan_absolute(abs_angle)) 30 | pan_relative(abs_angle - angle_pan); 31 | } 32 | 33 | void ptz::tilt(const double abs_angle) 34 | { 35 | if (!tilt_absolute(abs_angle)) 36 | tilt_relative(abs_angle - angle_tilt); 37 | } 38 | 39 | void ptz::operator()() 40 | { 41 | } 42 | -------------------------------------------------------------------------------- /src/source_filesystem_jpeg.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_filesystem_jpeg : public source 10 | { 11 | private: 12 | const std::string path; 13 | 14 | public: 15 | source_filesystem_jpeg(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & path, const double fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 16 | ~source_filesystem_jpeg(); 17 | 18 | void operator()() override; 19 | }; 20 | -------------------------------------------------------------------------------- /src/source_ffmpeg.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_ffmpeg : public source 10 | { 11 | private: 12 | const std::string url; 13 | const bool tcp; 14 | 15 | public: 16 | source_ffmpeg(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & url, const bool tcp, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 17 | ~source_ffmpeg(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /examples/video4linux.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "debug"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "video source"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 640; 15 | height = 480; 16 | } 17 | }) 18 | 19 | # output url will then be e.g.: 20 | # http://localhost:8070/stream.mjpeg?inst=video%20input 21 | global-http-server = ( 22 | { 23 | id = "2-1"; 24 | descr = "mjpeg out"; 25 | listen-adapter = "0.0.0.0"; 26 | listen-port = 8070; 27 | fps = 15; 28 | quality = 75; 29 | stylesheet = "stylesheet.css"; 30 | time-limit = -1; 31 | resize-width = -1; 32 | resize-height = -1; 33 | motion-compatible = false; 34 | allow-admin = false; 35 | archive-access = false; 36 | is-rest = false; 37 | } 38 | ) 39 | -------------------------------------------------------------------------------- /examples/mjpeg-multiplexer.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "debug"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "camera source"; 12 | type = "mjpeg"; 13 | # replace this 14 | url = "http://mycamera/stream.mjpeg"; 15 | } 16 | }) 17 | 18 | # output url will then be e.g.: 19 | # http://localhost:8070/stream.mjpeg?inst=video%20input 20 | global-http-server = ( 21 | { 22 | id = "2-1"; 23 | descr = "mjpeg out"; 24 | listen-adapter = "0.0.0.0"; 25 | listen-port = 8070; 26 | fps = 2.5; 27 | quality = 75; 28 | stylesheet = "stylesheet.css"; 29 | time-limit = -1; 30 | resize-width = -1; 31 | resize-height = -1; 32 | motion-compatible = false; 33 | allow-admin = false; 34 | archive-access = false; 35 | is-rest = false; 36 | } 37 | ) 38 | -------------------------------------------------------------------------------- /src/filter_mirror_h.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | 6 | #include "gen.h" 7 | #include "filter_mirror_h.h" 8 | 9 | filter_mirror_h::filter_mirror_h() 10 | { 11 | } 12 | 13 | filter_mirror_h::~filter_mirror_h() 14 | { 15 | } 16 | 17 | void filter_mirror_h::apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) 18 | { 19 | for(int y=0; y 4 | #include 5 | 6 | #include "source.h" 7 | #include "picio.h" 8 | 9 | class source_gstreamer : public source 10 | { 11 | private: 12 | const std::string pipeline; 13 | 14 | transformer_t tf; 15 | 16 | public: 17 | source_gstreamer(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & pipeline, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 18 | virtual ~source_gstreamer(); 19 | 20 | void operator()() override; 21 | }; 22 | -------------------------------------------------------------------------------- /src/ptz.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include "interface.h" 5 | 6 | class ptz : public interface 7 | { 8 | protected: 9 | double angle_pan { 0. }, angle_tilt { 0. }; 10 | 11 | virtual bool pan_relative(const double angle) = 0; 12 | virtual bool tilt_relative(const double angle) = 0; 13 | virtual bool pan_absolute(const double angle) = 0; 14 | virtual bool tilt_absolute(const double angle) = 0; 15 | 16 | public: 17 | ptz(); 18 | virtual ~ptz(); 19 | 20 | static ptz * check_is_supported(const int fd); 21 | 22 | virtual void pan(const double abs_angle); 23 | virtual void tilt(const double abs_angle); 24 | virtual void reset_to_center() = 0; 25 | 26 | double get_pan() const { return angle_pan; } 27 | double get_tilt() const { return angle_tilt; } 28 | 29 | virtual void operator()(); 30 | }; 31 | -------------------------------------------------------------------------------- /src/target_jpeg.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | 5 | class target_jpeg : public target 6 | { 7 | private: 8 | const int quality; 9 | 10 | int f_nr { 0 }; 11 | bool is_start { true }; 12 | 13 | std::string write_frame(video_frame * put_f); 14 | 15 | public: 16 | target_jpeg(const std::string & id, const std::string & descr, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int quality, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 17 | virtual ~target_jpeg(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/source_http_mjpeg.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_http_mjpeg : public source 10 | { 11 | private: 12 | const std::string url; 13 | const bool ignore_cert; 14 | 15 | public: 16 | source_http_mjpeg(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & url, const bool ignore_cert, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 17 | virtual ~source_http_mjpeg(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/filter-plugins/demo.c: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | 5 | void * init_filter(const char *const parameter) 6 | { 7 | // you can use the parameter for anything you want 8 | // e.g. the filename of a configuration file or 9 | // maybe a variable or whatever 10 | 11 | // what you return here, will be given as a parameter 12 | // to apply_filter 13 | 14 | return NULL; 15 | } 16 | 17 | void apply_filter(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result) 18 | { 19 | const size_t bytes = w * h * 3; 20 | 21 | memcpy(result, current_frame, bytes); 22 | 23 | for(size_t i=0; i 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_http_bmp : public source 10 | { 11 | private: 12 | const std::string url, auth; 13 | const bool ignore_cert; 14 | 15 | public: 16 | source_http_bmp(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & url, const bool ignore_cert, const std::string & auth, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 17 | ~source_http_bmp(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/source_http_png.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2022 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_http_png : public source 10 | { 11 | private: 12 | const std::string url, auth; 13 | const bool ignore_cert; 14 | 15 | public: 16 | source_http_png(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & url, const bool ignore_cert, const std::string & auth, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 17 | ~source_http_png(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/view_html_grid.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "cfg.h" 7 | #include "view.h" 8 | 9 | class view_html_grid : public view 10 | { 11 | private: 12 | const int grid_width, grid_height; 13 | const double switch_interval; 14 | 15 | video_frame * get_frame(const bool handle_failure, const uint64_t after) override { return { }; } 16 | 17 | public: 18 | view_html_grid(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, const int gwidth, const int gheight, const double switch_interval, const int jpeg_quality); 19 | virtual ~view_html_grid(); 20 | 21 | std::string get_html(const std::map & pars) const override; 22 | 23 | void operator()() override; 24 | }; 25 | -------------------------------------------------------------------------------- /src/source_http_jpeg.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | class source_http_jpeg : public source 10 | { 11 | private: 12 | const std::string url, auth; 13 | const bool ignore_cert; 14 | 15 | public: 16 | source_http_jpeg(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & url, const bool ignore_cert, const std::string & auth, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 17 | ~source_http_jpeg(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/motion_trigger_other_source.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | #include "cfg.h" 6 | #include "motion_trigger.h" 7 | 8 | class filter; 9 | class source; 10 | class target; 11 | 12 | class motion_trigger_other_source : public motion_trigger 13 | { 14 | private: 15 | source *const hr_s; 16 | instance *const lr_motion_trigger; 17 | 18 | std::atomic_bool motion_triggered { false }; 19 | 20 | public: 21 | motion_trigger_other_source(const std::string & id, const std::string & descr, source *const hr_s, instance *const lr_motion_trigger, std::vector *const targets, const std::map & detection_parameters, schedule *const sched); 22 | virtual ~motion_trigger_other_source(); 23 | 24 | bool check_motion() override { return motion_triggered; } 25 | 26 | void operator()() override; 27 | }; 28 | -------------------------------------------------------------------------------- /src/v4l2_loopback.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_LIBV4L2 == 1 5 | #include 6 | #include 7 | #include 8 | 9 | #include "interface.h" 10 | #include "picio.h" 11 | 12 | class filter; 13 | class source; 14 | 15 | class v4l2_loopback : public interface 16 | { 17 | private: 18 | source *const s; 19 | const double fps; 20 | const std::string dev, pixel_format; 21 | const std::vector *const filters; 22 | instance *const inst; 23 | transformer_t th; 24 | 25 | public: 26 | v4l2_loopback(const std::string & id, const std::string & descr, source *const s, const double fps, const std::string & dev, const std::string & pixel_format, const std::vector *const filters, instance *const inst); 27 | virtual ~v4l2_loopback(); 28 | 29 | void operator()() override; 30 | }; 31 | #endif 32 | -------------------------------------------------------------------------------- /src/controls.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | 5 | class controls 6 | { 7 | protected: 8 | int default_brightness { 0 }, default_contrast { 0 }, default_saturation { 0 }; 9 | 10 | public: 11 | controls(); 12 | virtual ~controls(); 13 | 14 | virtual void reset(); 15 | 16 | virtual bool has_controls() const { return false; } 17 | 18 | virtual bool has_brightness(); 19 | virtual int get_brightness(); 20 | virtual void set_brightness(const int b); 21 | 22 | virtual bool has_contrast(); 23 | virtual int get_contrast(); 24 | virtual void set_contrast(const int c); 25 | 26 | virtual bool has_saturation(); 27 | virtual int get_saturation(); 28 | virtual void set_saturation(const int s); 29 | 30 | virtual bool requires_apply() { return false; } 31 | virtual void apply(uint8_t *const target, const int w, const int h); 32 | }; 33 | -------------------------------------------------------------------------------- /examples/multicast-tx.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "info"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "regular video"; 8 | 9 | source = { 10 | id = "v4l-src"; 11 | descr = "v4l source - regular video"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 1280; 15 | height = 720; 16 | max-fps = -1.0; 17 | pixel-format = "bla"; 18 | resize-width = -1; 19 | resize-height = -1; 20 | enable-controls = false; 21 | } 22 | 23 | targets = ({ 24 | id = "multicast"; 25 | descr = "gstreamer"; 26 | fps = -1.0; 27 | format = "gstreamer"; 28 | pipeline = "appsrc name=\"constatus\" ! queue ! videoconvert ! video/x-raw ! x264enc noise-reduction=10000 tune=zerolatency bitrate=2500 speed-preset=\"fast\" byte-stream=true threads=4 key-int-max=15 intra-refresh=true ! h264parse ! rtph264pay config-interval=1 ! udpsink host=224.1.1.1 port=5000 auto-multicast=true"; 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /src/announce_upnp.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_RYGEL == 1 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "gen.h" 12 | #include "cfg.h" 13 | #include "interface.h" 14 | 15 | class http_server; 16 | 17 | class announce_upnp : public interface 18 | { 19 | private: 20 | configuration_t *const cfg; 21 | const std::vector announce_ids; 22 | const std::vector interfaces; 23 | 24 | GMainLoop *loop { nullptr }; 25 | 26 | public: 27 | announce_upnp(configuration_t *const cfg, const std::string & id, const std::string & descr, const std::vector & announce_ids, const std::vector &interfaces); 28 | virtual ~announce_upnp(); 29 | 30 | virtual void stop(); 31 | 32 | virtual void operator()() override; 33 | }; 34 | #endif 35 | -------------------------------------------------------------------------------- /src/view_all.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "cfg.h" 7 | #include "view_ss.h" 8 | 9 | class view_all : public view_ss 10 | { 11 | private: 12 | const int grid_width{ 1 }, grid_height{ 1 }; 13 | uint64_t *ts_list{ nullptr }; 14 | uint8_t *work{ nullptr }; 15 | video_frame *prev_frame { nullptr }; 16 | 17 | public: 18 | view_all(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const int gwidth, const int gheight, const std::vector & sources, const double switch_interval, std::vector *const filters, const int jpeg_quality); 19 | virtual ~view_all(); 20 | 21 | std::string get_html(const std::map & pars) const override; 22 | 23 | video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 24 | }; 25 | -------------------------------------------------------------------------------- /src/controls_software.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "controls.h" 4 | 5 | class controls_software : public controls 6 | { 7 | private: 8 | int brightness{ 32767 }, contrast{ 32767 }, saturation{ 32767 }; 9 | 10 | public: 11 | controls_software(); 12 | virtual ~controls_software(); 13 | 14 | virtual void reset(); 15 | 16 | virtual bool has_controls() const { return true; } 17 | 18 | virtual bool has_brightness(); 19 | virtual int get_brightness(); 20 | virtual void set_brightness(const int b); 21 | 22 | virtual bool has_contrast(); 23 | virtual int get_contrast(); 24 | virtual void set_contrast(const int c); 25 | 26 | virtual bool has_saturation(); 27 | virtual int get_saturation(); 28 | virtual void set_saturation(const int s); 29 | 30 | virtual bool requires_apply() { return true; } 31 | virtual void apply(uint8_t *const target, const int w, const int h); 32 | }; 33 | -------------------------------------------------------------------------------- /src/audio_trigger.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #include 5 | #include 6 | 7 | #include "cfg.h" 8 | #include "interface.h" 9 | 10 | class audio; 11 | class source; 12 | 13 | class audio_trigger : public interface 14 | { 15 | protected: 16 | instance *const i; 17 | source *const s; 18 | audio *const a; 19 | const int threshold; 20 | const size_t min_n_triggers; 21 | 22 | const std::vector trigger_targets; 23 | 24 | std::vector event_clients; 25 | 26 | void register_notifiers(); 27 | void unregister_notifiers(); 28 | 29 | public: 30 | audio_trigger(const std::string & id, const std::string & descr, instance *const i, source *const s, const int threshold, const size_t min_n_triggers, const std::vector & trigger_targets); 31 | virtual ~audio_trigger(); 32 | 33 | virtual void operator()() override; 34 | }; 35 | -------------------------------------------------------------------------------- /src/target_extpipe.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | #include "picio.h" 5 | 6 | class target_extpipe : public target 7 | { 8 | private: 9 | const int quality; 10 | const std::string cmd; 11 | transformer_t th; 12 | 13 | void store_frame(video_frame *const put_f, FILE *const p_fd); 14 | 15 | public: 16 | target_extpipe(const std::string & id, const std::string & descr, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int quality, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, const std::string & cmd, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 17 | virtual ~target_extpipe(); 18 | 19 | void operator()() override; 20 | }; 21 | -------------------------------------------------------------------------------- /src/filter_overlay_on_motion.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class interface; 9 | 10 | class filter_overlay_on_motion : public filter 11 | { 12 | private: 13 | instance *const i; 14 | source *const cks; 15 | resize *const r; 16 | const int display_time_ms; 17 | 18 | std::atomic_bool changed { false }; 19 | uint64_t since { 0 }; 20 | 21 | public: 22 | filter_overlay_on_motion(instance *const i, source *const cks, resize *const r, const int display_time_ms); 23 | ~filter_overlay_on_motion(); 24 | 25 | void notify_thread_of_event(const std::string & subject) override; 26 | 27 | bool uses_in_out() const override { return false; } 28 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 29 | }; 30 | -------------------------------------------------------------------------------- /src/controls.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "controls.h" 3 | 4 | controls::controls() 5 | { 6 | } 7 | 8 | controls::~controls() 9 | { 10 | } 11 | 12 | void controls::reset() 13 | { 14 | } 15 | 16 | bool controls::has_brightness() 17 | { 18 | return false; 19 | } 20 | 21 | int controls::get_brightness() 22 | { 23 | return 32767; 24 | } 25 | 26 | void controls::set_brightness(const int b) 27 | { 28 | } 29 | 30 | bool controls::has_contrast() 31 | { 32 | return false; 33 | } 34 | 35 | int controls::get_contrast() 36 | { 37 | return 32767; 38 | } 39 | 40 | void controls::set_contrast(const int c) 41 | { 42 | } 43 | 44 | bool controls::has_saturation() 45 | { 46 | return false; 47 | } 48 | 49 | int controls::get_saturation() 50 | { 51 | return 32767; 52 | } 53 | 54 | void controls::set_saturation(const int s) 55 | { 56 | } 57 | 58 | void controls::apply(uint8_t *const target, const int w, const int h) 59 | { 60 | } 61 | -------------------------------------------------------------------------------- /src/filter-plugins/demo2.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | 8 | void * init_filter(const char *const parameter) 9 | { 10 | // you can use the parameter for anything you want 11 | // e.g. the filename of a configuration file or 12 | // maybe a variable or whatever 13 | 14 | // what you return here, will be given as a parameter 15 | // to apply_filter 16 | 17 | return NULL; 18 | } 19 | 20 | void apply_filter(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result) 21 | { 22 | const size_t bytes = w * h * 3; 23 | 24 | memcpy(result, current_frame, bytes); 25 | 26 | for(size_t i=0; i 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | #include "pixelflood.h" 9 | #include "utils.h" 10 | 11 | class source_pixelflood : public source 12 | { 13 | private: 14 | pthread_t th_client; 15 | const listen_adapter_t la; 16 | const int pixel_size; 17 | const pixelflood_protocol_t pp; 18 | 19 | uint8_t *frame_buffer; 20 | 21 | public: 22 | source_pixelflood(const std::string & id, const std::string & descr, const std::string & exec_failure, const listen_adapter_t & la, const int pixel_size, const pixelflood_protocol_t pp, const double max_fps, const int w, const int h, const int loglevel, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 23 | ~source_pixelflood(); 24 | 25 | void operator()() override; 26 | }; 27 | -------------------------------------------------------------------------------- /src/target_ffmpeg.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_FFMPEG == 1 5 | #include "target.h" 6 | 7 | class filter; 8 | class source; 9 | 10 | class target_ffmpeg : public target 11 | { 12 | private: 13 | const std::string parameters, type; 14 | unsigned bitrate; 15 | 16 | public: 17 | target_ffmpeg(const std::string & id, const std::string & descr, const std::string & parameters, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int max_time, const double interval, const std::string & type, const int bitrate, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, const double override_fps, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 18 | virtual ~target_ffmpeg(); 19 | 20 | void operator()() override; 21 | }; 22 | #endif 23 | -------------------------------------------------------------------------------- /src/target_new_source.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | 5 | class target_new_source : public target 6 | { 7 | private: 8 | const std::string new_s_id; 9 | const std::string new_s_descr; 10 | const bool rot90; 11 | const std::map text_feeds; 12 | 13 | std::mutex new_source_lock; 14 | source *new_source { nullptr }; 15 | 16 | public: 17 | target_new_source(const std::string & id, const std::string & descr, source *const s, const double interval, const std::vector *const filters, configuration_t *const cfg, const std::string & new_s_id, const std::string & new_s_descr, schedule *const sched, const bool rot90, const std::map & text_feeds); 18 | virtual ~target_new_source(); 19 | 20 | source * get_new_source(); 21 | 22 | void operator()() override; 23 | }; 24 | -------------------------------------------------------------------------------- /src/gen.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "video_frame.h" 9 | 10 | typedef struct { 11 | std::string msg; 12 | bool critical; 13 | } error_state_t; 14 | 15 | typedef struct { 16 | uint8_t r, g, b; 17 | } rgb_t; 18 | 19 | typedef struct 20 | { 21 | uint64_t ts; 22 | int w, h; 23 | uint16_t *data; 24 | size_t len; 25 | encoding_t e; 26 | } depth_frame_t; 27 | 28 | typedef struct 29 | { 30 | uint64_t ts; 31 | int sample_rate; 32 | short *data; 33 | size_t len; 34 | } audio_frame_t; 35 | 36 | typedef struct 37 | { 38 | video_frame *vf; 39 | depth_frame_t *depth_frame; 40 | audio_frame_t *audio_frame; 41 | } bundle_t; 42 | 43 | extern struct timeval app_start_ts; 44 | 45 | // int multiply to size_t; to silence lgtm.com 46 | #define IMS(w, h, n) (size_t(w) * size_t(h) * size_t(n)) 47 | #define IMUL(w, h, n) ((unsigned long)(w) * (unsigned long)(h) * (unsigned long)(n)) 48 | -------------------------------------------------------------------------------- /src/view_pip.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cfg.h" 8 | #include "view_ss.h" 9 | 10 | class view_pip : public view_ss 11 | { 12 | private: 13 | std::mutex prev_frame_lock; 14 | video_frame *prev_frame { nullptr }; 15 | 16 | uint64_t new_ts { 0 }; 17 | 18 | std::mutex frames_lock; 19 | std::condition_variable frames_cv; 20 | std::vector frames; 21 | 22 | public: 23 | view_pip(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, std::vector *const filters, const int jpeg_quality); 24 | virtual ~view_pip(); 25 | 26 | std::string get_html(const std::map & pars) const override; 27 | 28 | video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 29 | 30 | virtual void operator()() override; 31 | }; 32 | -------------------------------------------------------------------------------- /examples/libcamera.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "debug"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "libcamera"; 12 | type = "libcamera"; 13 | # # rpi: 14 | # device = "/base/soc/i2c0mux/i2c@1/imx219@10"; 15 | # some hp laptop 16 | device = "\_SB_.PCI0.XHC_.RHUB.HS06-6:1.0-05c8:03d2"; 17 | # (see also output of 'list-libcamera') 18 | width = 1280; 19 | height = 720; 20 | } 21 | }) 22 | 23 | # output url will then be e.g.: 24 | # http://localhost:8070/stream.mjpeg?inst=video%20input 25 | global-http-server = ( 26 | { 27 | id = "2-1"; 28 | descr = "mjpeg out"; 29 | listen-adapter = "0.0.0.0"; 30 | listen-port = 8070; 31 | fps = 15.0; 32 | quality = 75; 33 | stylesheet = "stylesheet.css"; 34 | time-limit = -1; 35 | resize-width = -1; 36 | resize-height = -1; 37 | motion-compatible = false; 38 | allow-admin = false; 39 | archive-access = false; 40 | is-rest = false; 41 | } 42 | ) 43 | -------------------------------------------------------------------------------- /src/filter-plugins/cairo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | cairo_surface_t * rgb_to_cairo(const uint8_t *const in, const int w, const int h, uint32_t **temp) 7 | { 8 | size_t n = w * h; 9 | *temp = (uint32_t *)valloc(n * 4); 10 | 11 | const uint8_t *win = in; 12 | uint32_t *wout = *temp; 13 | 14 | for(size_t i=0; i> 16; 33 | *out++ = temp >> 8; 34 | *out++ = temp; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/filter-plugins/README: -------------------------------------------------------------------------------- 1 | KEEP-ALIVE 2 | ========== 3 | Blinks a dot in the upper corner if the feed is alive 4 | 5 | 6 | RED INVERTER 7 | ============ 8 | demo is a filter in C, inverting the red channel 9 | 10 | 11 | SWAP RED/BLUE 12 | ============= 13 | demo2 is a filter in C++, swapping the red and the blue channel 14 | 15 | 16 | CONTOURS 17 | ======== 18 | demoocv is a filter using OpenCV, it finds the contours in an image 19 | 20 | 21 | MQTT FEED 22 | ========= 23 | mqtt reads from an mqtt source and adds the result as text in the stream 24 | 'par' should contain: 25 | mqtt_host:mqtt_port:mqtt_topic:nr_of_lines_to_show 26 | 27 | 28 | MQTT OVERLAY 29 | ============ 30 | switches on an overlay picture when '1', 'true' or 'on' is put in the mqtt-topic 31 | 'par' should contain: 32 | mqtt_host:mqtt_port:mqtt_topic:png_overlay_path 33 | make lib6 34 | 35 | 36 | Using plugins 37 | ------------- 38 | 39 | filters = ( 40 | { 41 | type = "filter-plugin"; 42 | file = "filter-plugins/demoocv.so.0.1"; 43 | par = ""; 44 | } 45 | ) 46 | -------------------------------------------------------------------------------- /src/filter.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "cfg.h" 8 | #include "interface.h" 9 | 10 | // NULL filter 11 | class filter : public interface 12 | { 13 | protected: 14 | filter(); 15 | 16 | public: 17 | virtual ~filter(); 18 | 19 | virtual bool uses_in_out() const { return true; } 20 | virtual void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out); 21 | virtual void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out); 22 | }; 23 | 24 | void apply_filters(instance *const i, interface *const specific_int, const std::vector *const filters, const uint8_t *const prev, uint8_t *const work, const uint64_t ts, const int w, const int h); 25 | 26 | void free_filters(const std::vector *filters); 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # (C) 2017-2023 by Folkert van Heusden, released under MIT license 2 | 3 | NAME="constatus" 4 | PREFIX=/usr 5 | VERSION="6.0" 6 | 7 | constatus: 8 | mkdir -p build && cd build && cmake .. && make 9 | 10 | install: constatus 11 | install -Dm755 constatus ${DESTDIR}${PREFIX}/bin/constatus 12 | install -Dm755 motion-to-constatus.py ${DESTDIR}${PREFIX}/share/doc/constatus/motion-to-constatus.py 13 | mkdir -p ${DESTDIR}${PREFIX}/share/doc/constatus 14 | install -Dm644 constatus.cfg ${DESTDIR}${PREFIX}/share/doc/constatus/example.cfg 15 | install -Dm644 man/constatus.1 ${DESTDIR}${PREFIX}/share/man/man1/constatus.1 16 | 17 | uninstall: 18 | rm -f ${DESTDIR}${PREFIX}/bin/constatus 19 | 20 | clean: 21 | rm -rf build 22 | 23 | package: clean 24 | mkdir constatus-$(VERSION) 25 | cp -a man/ src examples README.md constatus.cfg debian favicon.ico stylesheet.css LICENSE CMakeLists.txt config.h.in motion-to-constatus.py README.rest constatus-$(VERSION) 26 | tar czf ../constatus_$(VERSION).orig.tar.gz constatus-$(VERSION) 27 | rm -rf constatus-$(VERSION) 28 | -------------------------------------------------------------------------------- /src/error.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "log.h" 11 | #include "utils.h" 12 | 13 | void error_exit(const bool se, const char *format, ...) 14 | { 15 | int e = errno; 16 | va_list ap; 17 | 18 | va_start(ap, format); 19 | char *temp = NULL; 20 | if (vasprintf(&temp, format, ap) == -1) 21 | puts(format); // last resort 22 | va_end(ap); 23 | 24 | fprintf(stderr, "%s\n", temp); 25 | lognee(LL_ERR, "%s", temp); 26 | syslog(LOG_ERR, "%s", temp); 27 | 28 | if (se && e) { 29 | fprintf(stderr, "errno: %d (%s)\n", e, strerror(e)); 30 | lognee(LL_ERR, "errno: %d (%s)", e, strerror(e)); 31 | syslog(LOG_ERR, "errno: %d (%s)", e, strerror(e)); 32 | } 33 | 34 | free(temp); 35 | 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | void cpt(const int err) 40 | { 41 | if (err) 42 | error_exit(true, "pthread error %s", strerror(errno)); 43 | } 44 | -------------------------------------------------------------------------------- /examples/pixelflood.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "debug"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "video source"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 640; 15 | height = 480; 16 | } 17 | 18 | targets = ( 19 | { 20 | id = "1-2"; 21 | descr = "send to pixelflood server"; 22 | 23 | handle-failure = true; 24 | 25 | fps = -1.0; 26 | 27 | format = "pixelflood"; 28 | 29 | # - pixelflood 30 | # requires a couple of extra parameters: 31 | host = "10.208.42.159"; 32 | port = 5004; 33 | # dimensions of the pixelflood server: 34 | pf-w = 128; 35 | pf-h = 32; 36 | # offset in the pixelflood server: 37 | x-off = 0; 38 | y-off = 0; 39 | # pixelflood version: 40 | pp = "tcp-txt"; # the protocol version that accepts "PX x y rrggbb\n" via a TCP socket 41 | # pp = "udp-bin"; # the protocol version that accepts a binary packet via a UDP socket 42 | } 43 | ) 44 | }) 45 | -------------------------------------------------------------------------------- /src/controls_v4l.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_LIBV4L2 == 1 5 | #include "controls.h" 6 | 7 | class controls_v4l : public controls 8 | { 9 | private: 10 | const int fd; 11 | 12 | int brightness_min { 0 }, brightness_max { 0 }; 13 | int contrast_min { 0 }, contrast_max { 0 }; 14 | int saturation_min { 0 }, saturation_max { 0 }; 15 | 16 | public: 17 | controls_v4l(const int fd); 18 | virtual ~controls_v4l(); 19 | 20 | virtual void reset() override; 21 | 22 | virtual bool has_controls() const override { return true; } 23 | 24 | bool has_brightness() override; 25 | int get_brightness() override; 26 | void set_brightness(const int b) override; 27 | 28 | bool has_contrast() override; 29 | int get_contrast() override; 30 | void set_contrast(const int b) override; 31 | 32 | bool has_saturation() override; 33 | int get_saturation() override; 34 | void set_saturation(const int b) override; 35 | 36 | void apply(uint8_t *const target, const int w, const int h) override; 37 | }; 38 | #endif 39 | -------------------------------------------------------------------------------- /src/filter_add_text.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class interface; 9 | class feed; 10 | 11 | void find_text_dim(const char *const in, int *const n_lines, int *const n_cols); 12 | 13 | std::string unescape(const std::string & in, const uint64_t ts, instance *const i, interface *const specific_int, const std::map & text_feeds); 14 | 15 | class filter_add_text : public filter 16 | { 17 | private: 18 | const std::string what; 19 | const pos_t tp; 20 | const std::map text_feeds; 21 | 22 | public: 23 | filter_add_text(const std::string & what, const pos_t tp, const std::map & text_feeds); 24 | ~filter_add_text(); 25 | 26 | bool uses_in_out() const override { return false; } 27 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 28 | }; 29 | -------------------------------------------------------------------------------- /examples/browser.cfg: -------------------------------------------------------------------------------- 1 | logfile = "constatus.log"; 2 | log-level = "info"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "my instance name"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "video4linux source"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 1280; 15 | height = 720; 16 | } 17 | 18 | targets = ( 19 | { 20 | id = "1-6"; 21 | class = "write everything to disk"; 22 | 23 | path = "./out"; 24 | 25 | quality = 75; 26 | 27 | restart-interval = 1800; 28 | 29 | fps = 5.0; 30 | override-fps = -1.0; 31 | 32 | format = "ffmpeg"; 33 | ffmpeg-type = "mp4"; 34 | # 2 megabit 35 | bitrate = 2000000; 36 | } 37 | ) 38 | }) 39 | 40 | global-http-server = ({ 41 | id = "9-1"; 42 | descr = "global http interface"; 43 | listen-adapter = "0.0.0.0"; 44 | listen-port = 8070; 45 | fps = 5.0; 46 | quality = 75; 47 | time-limit = -1; 48 | resize-width = -1; 49 | resize-height = -1; 50 | motion-compatible = false; 51 | allow-admin = true; 52 | archive-access = true; 53 | snapshot-dir = "./out"; 54 | }) 55 | -------------------------------------------------------------------------------- /src/source_delay.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include "source.h" 5 | 6 | class source_delay : public source 7 | { 8 | private: 9 | std::vector frames; 10 | mutable std::shared_mutex frames_lock; 11 | 12 | source *const s; 13 | const size_t n_frames; 14 | const double max_fps; 15 | 16 | uint64_t last_ts { 0 }; 17 | 18 | video_frame *prev { nullptr }; 19 | 20 | public: 21 | source_delay(const std::string & id, const std::string & descr, const std::string & exec_failure, source *const s, const int jpeg_quality, const int n_frames, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int ll, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const std::map & text_feeds); 22 | virtual ~source_delay(); 23 | 24 | virtual video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 25 | uint64_t get_current_ts() const override; 26 | 27 | virtual void operator()() override; 28 | }; 29 | -------------------------------------------------------------------------------- /src/source_plugin.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "source.h" 8 | 9 | typedef void *(* sp_init_plugin_t)(source *const s, const char *const argument); 10 | typedef void (* sp_uninit_plugin_t)(void *arg); 11 | 12 | class source_plugin : public source 13 | { 14 | private: 15 | sp_init_plugin_t init_plugin; 16 | sp_uninit_plugin_t uninit_plugin; 17 | void *arg; 18 | void *library; 19 | 20 | public: 21 | source_plugin(const std::string & id, const std::string & descr, const int w, const int h, const std::string & exec_failure, const std::string & plugin_filename, const std::string & plugin_arg, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio); 22 | ~source_plugin(); 23 | 24 | void operator()() override; 25 | }; 26 | -------------------------------------------------------------------------------- /src/view_3d.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "cfg.h" 7 | #include "view_ss.h" 8 | 9 | typedef enum { view_3d_sidebyside, view_3d_topbottom, view_3d_lines, view_3d_columns, view_3d_checkerboard, view_3d_framesequence, view_3d_redgreen, view_3d_redblue } view_3d_mode_t; 10 | 11 | class view_3d : public view_ss 12 | { 13 | private: 14 | const view_3d_mode_t v3m; 15 | 16 | std::mutex prev_frame_lock; 17 | uint8_t *l_prev_frame { nullptr }; 18 | uint8_t *r_prev_frame { nullptr }; 19 | 20 | bool left { true }; 21 | 22 | public: 23 | view_3d(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, std::vector *const filters, const view_3d_mode_t v3m, const int jpeg_quality); 24 | virtual ~view_3d(); 25 | 26 | std::string get_html(const std::map & pars) const override; 27 | 28 | virtual video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 29 | }; 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Folkert van Heusden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/filter_add_scaled_text.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "draw_text.h" 7 | #include "filter.h" 8 | 9 | class interface; 10 | 11 | class filter_add_scaled_text : public filter 12 | { 13 | private: 14 | std::string what; 15 | draw_text *font { nullptr }; 16 | const int x; 17 | const int y; 18 | const int font_size; 19 | const int width; 20 | const std::optional bg; 21 | const rgb_t col; 22 | const bool invert; 23 | const std::map text_feeds; 24 | 25 | public: 26 | filter_add_scaled_text(const std::string & what, const std::string & font_file, const int x, const int y, const int font_size, const int width, std::optional bg, const rgb_t col, const bool invert, const std::map & text_feeds); 27 | ~filter_add_scaled_text(); 28 | 29 | bool uses_in_out() const override { return false; } 30 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 31 | }; 32 | -------------------------------------------------------------------------------- /src/source_other.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2022 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "source.h" 9 | 10 | typedef struct { 11 | int x, y, w, h; 12 | } cut_t; 13 | 14 | class source_other : public source 15 | { 16 | private: 17 | const std::string o_inst; 18 | const std::string o_id; 19 | source *const other; 20 | const std::optional cut; 21 | const int rotation_angle; 22 | 23 | void crop(video_frame *const in, video_frame **const out, const cut_t & cut); 24 | 25 | public: 26 | source_other(const std::string & id, const std::string & descr, source *const other, const std::string & exec_failure, const int loglevel, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, resize *const r, const int resize_w, const int resize_h, const std::optional & cut, const int rotate, const std::map & text_feeds, const bool keep_aspectratio); 27 | ~source_other(); 28 | 29 | void operator()() override; 30 | }; 31 | -------------------------------------------------------------------------------- /src/source_black.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "error.h" 8 | #include "http_client.h" 9 | #include "source.h" 10 | #include "source_black.h" 11 | #include "filter_add_text.h" 12 | #include "picio.h" 13 | #include "filter.h" 14 | #include "log.h" 15 | #include "utils.h" 16 | #include "controls.h" 17 | 18 | source_black::source_black(const std::string & id, const std::string & descr, const int width, const int height, controls *const c, const std::map & text_feeds) : source(id, descr, "", width, height, nullptr, c, 1, text_feeds, false) 19 | { 20 | } 21 | 22 | source_black::~source_black() 23 | { 24 | delete c; 25 | } 26 | 27 | void source_black::operator()() 28 | { 29 | } 30 | 31 | video_frame * source_black::get_frame(const bool handle_failure, const uint64_t after) 32 | { 33 | size_t len = IMS(this->width, this->height, 3); 34 | 35 | uint8_t *p = (uint8_t *)allocate_0x00(len); 36 | 37 | return new video_frame(get_meta(), jpeg_quality, get_us(), width, height, p, len, E_RGB); 38 | } 39 | -------------------------------------------------------------------------------- /src/target_gwavi.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | 4 | #if HAVE_LIBGWAVI == 1 5 | extern "C" { 6 | #include 7 | } 8 | 9 | #include "target.h" 10 | 11 | class target_gwavi : public target 12 | { 13 | private: 14 | const int quality { 99 }; 15 | gwavi_t *gwavi { nullptr }; 16 | int f_nr { 0 }; 17 | std::string name; 18 | int fps { 25 }; 19 | 20 | void put_frame(video_frame *const f); 21 | void open_file(); 22 | void close_file(); 23 | 24 | public: 25 | target_gwavi(const std::string & id, const std::string & descr, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int quality, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, const double override_fps, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 26 | virtual ~target_gwavi(); 27 | 28 | void operator()(); 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /examples/crop.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "info"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "libcamera"; 12 | type = "libcamera"; 13 | device = "\_SB_.PC00.XHCI.RHUB.HS07-7:1.0-322e:202c"; 14 | width = 1280; 15 | height = 720; 16 | } 17 | }, 18 | { 19 | instance-name = "crop"; 20 | 21 | source = { 22 | id = "3-1"; 23 | descr = "crop other source"; 24 | type = "other-source"; 25 | # source from which pixels are copied 26 | other-id = "1-1"; 27 | cut-x = 100; 28 | cut-y = 100; 29 | cut-w = 400; 30 | cut-h = 250; 31 | } 32 | }) 33 | 34 | global-http-server = ( 35 | { 36 | id = "2-1"; 37 | descr = "mjpeg out"; 38 | listen-adapter = "0.0.0.0"; 39 | listen-port = 8070; 40 | fps = 15.0; 41 | quality = 75; 42 | stylesheet = "stylesheet.css"; 43 | time-limit = -1; 44 | resize-width = -1; 45 | resize-height = -1; 46 | motion-compatible = false; 47 | allow-admin = false; 48 | archive-access = false; 49 | is-rest = false; 50 | } 51 | ) 52 | -------------------------------------------------------------------------------- /src/target_pixelflood.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "target.h" 9 | #include "pixelflood.h" 10 | 11 | class schedule; 12 | 13 | class target_pixelflood : public target 14 | { 15 | private: 16 | const int quality; 17 | const std::string host; 18 | const int port; 19 | const int pw, ph; 20 | const pixelflood_protocol_t pp; 21 | const int xoff, yoff; 22 | 23 | int fd; 24 | struct sockaddr_in servaddr { 0 }; 25 | 26 | bool send_frame(const uint8_t *const data, const int w, const int h); 27 | 28 | public: 29 | target_pixelflood(const std::string & id, const std::string & descr, source *const s, const double interval, const std::vector *const filters, const double override_fps, configuration_t *const cfg, const std::string & ip_addr, const int port, const int pfw, const int pfh, const int quality, const pixelflood_protocol_t pp, const int xoff, const int yoff, const bool handle_failure, schedule *const sched); 30 | virtual ~target_pixelflood(); 31 | 32 | void operator()() override; 33 | }; 34 | -------------------------------------------------------------------------------- /src/filter_noise_neighavg.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | 5 | #include "gen.h" 6 | #include "filter_noise_neighavg.h" 7 | 8 | filter_noise_neighavg::filter_noise_neighavg() 9 | { 10 | } 11 | 12 | filter_noise_neighavg::~filter_noise_neighavg() 13 | { 14 | } 15 | 16 | void filter_noise_neighavg::apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) 17 | { 18 | for(int y = 1; y 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "error.h" 10 | #include "filter_draw.h" 11 | #include "picio.h" 12 | 13 | filter_draw::filter_draw(const int x, const int y, const int w, const int h, const rgb_t col) : x(x), y(y), w(w), h(h), col(col) 14 | { 15 | } 16 | 17 | filter_draw::~filter_draw() 18 | { 19 | } 20 | 21 | void filter_draw::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w_in, const int h_in, const uint8_t *const prev, uint8_t *const in_out) 22 | { 23 | int work_x = x < 0 ? x + w : x; 24 | int work_y = y < 0 ? y + h : y; 25 | 26 | int sx = std::min(work_x, w_in), sy = std::min(work_y, h_in); 27 | int ex = std::min(work_x + w, w_in), ey = std::min(work_y + h, h_in); 28 | 29 | for(int wy=sy; wy 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "filter_boost_contrast.h" 10 | 11 | filter_boost_contrast::filter_boost_contrast() 12 | { 13 | } 14 | 15 | filter_boost_contrast::~filter_boost_contrast() 16 | { 17 | } 18 | 19 | void filter_boost_contrast::apply(instance *const inst, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 20 | { 21 | uint8_t lowest_br = 255, highest_br = 0; 22 | 23 | for(int i=0; i highest_br) 29 | highest_br = g; 30 | } 31 | 32 | if (highest_br == lowest_br || (highest_br == 255 && lowest_br == 0)) 33 | return; 34 | 35 | double mul = 255.0 / (highest_br - lowest_br); 36 | // printf("%f\n", mul); 37 | 38 | uint8_t *p = in_out; 39 | uint8_t *const pend = p + w * h * 3; 40 | 41 | for(;p < pend; p++) 42 | *p = (*p - lowest_br) * mul; 43 | } 44 | -------------------------------------------------------------------------------- /examples/lcdproc-overlay.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "info"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "regular video"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "v4l source - regular video"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 1280; 15 | height = 720; 16 | max-fps = -1.0; 17 | 18 | filters = ({ 19 | type = "lcdproc"; 20 | font = "/usr/share/fonts/truetype/msttcorefonts/Courier_New.ttf"; 21 | x = 1; 22 | y = 1; 23 | w = 1278; 24 | h = 718; 25 | n-col = 40; 26 | n-row = 10; 27 | bg = true; 28 | color = "black"; 29 | }) 30 | } 31 | }) 32 | 33 | global-http-server = ( 34 | { 35 | id = "3-1"; 36 | descr = "global admin interface"; 37 | listen-adapter = "0.0.0.0"; 38 | listen-port = 8070; 39 | fps = 5.0; 40 | quality = 100; 41 | stylesheet = "stylesheet.css"; 42 | time-limit = -1; 43 | resize-width = -1; 44 | resize-height = -1; 45 | motion-compatible = false; 46 | allow-admin = true; 47 | archive-access = true; 48 | snapshot-dir = "./out"; 49 | dir-with-subdirs = true; 50 | is-rest = true; 51 | ssdp = true; 52 | websocket-privacy = false; 53 | } 54 | ) 55 | -------------------------------------------------------------------------------- /src/filter_average.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "filter_average.h" 10 | #include "log.h" 11 | #include "utils.h" 12 | 13 | filter_average::filter_average(const size_t average_n) : average_n(average_n) 14 | { 15 | } 16 | 17 | filter_average::~filter_average() 18 | { 19 | for(auto p : h_frames) 20 | free(p); 21 | } 22 | 23 | void filter_average::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 24 | { 25 | if (h_frames.size() > average_n) { 26 | free(h_frames.at(0)); 27 | h_frames.erase(h_frames.begin()); 28 | } 29 | 30 | size_t n_bytes = IMS(w, h, 3); 31 | uint8_t *copy = (uint8_t *)malloc(n_bytes); 32 | memcpy(copy, in_out, n_bytes); 33 | h_frames.push_back(copy); 34 | 35 | if (h_frames.size() < average_n) 36 | return; 37 | 38 | for(size_t p=0; p 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | bool verbose = argc >=2 && strcmp(argv[1], "-v") == 0; 8 | bool very_verbose = argc >=2 && strcmp(argv[1], "-vv") == 0; 9 | 10 | if (!very_verbose) 11 | libcamera::logSetTarget(libcamera::LoggingTargetNone); 12 | 13 | libcamera::CameraManager *lcm = new libcamera::CameraManager(); 14 | 15 | if (int rc = lcm->start(); rc != 0) { 16 | fprintf(stderr, "libcamera: %s", strerror(-rc)); 17 | return 1; 18 | } 19 | 20 | auto cams = lcm->cameras(); 21 | for(auto camera : cams) { 22 | printf("libcamera device: %s\n", camera.get()->id().c_str()); 23 | 24 | if (verbose) { 25 | std::unique_ptr configurations = camera->generateConfiguration({ libcamera::StreamRole::VideoRecording }); 26 | 27 | for(auto & configuration: *configurations) { 28 | printf(" %s\n", configuration.toString().c_str()); 29 | 30 | for(auto & format: configuration.formats().pixelformats()) 31 | printf(" %s: %s\n", format.toString().c_str(), configuration.formats().range(format).toString().c_str()); 32 | } 33 | } 34 | } 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /examples/interfacing-to-obs-studio.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "info"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ( 7 | { 8 | instance-name = "remote cam 1"; 9 | 10 | # some source 11 | source = { 12 | id = "1-1"; 13 | descr = "camera source"; 14 | max-fps=10.0; 15 | quality=75; 16 | type = "mjpeg"; 17 | url = "http://cameras:8083/stream.mjpeg?inst=foordoor"; 18 | } 19 | 20 | # this is it! here you select that everything from the source 21 | # define above goes to the video4linux loopback /dev/video7 22 | # so you need to open /dev/video7 (in this example) in e.g. obs 23 | # this loopback is described at https://github.com/umlaeute/v4l2loopback 24 | # you probably don't need to install it from source, in ubuntu 25 | # you only need to install 'v4l2loopback-dkms'. don't forget 26 | # to load the module of course, an example: 27 | # modprobe v4l2loopback exclusive_caps=1 card_label='test' devices=10 28 | video-loopback = { 29 | id = "1-2"; 30 | # you may need to select an other device here 31 | device = "/dev/video7"; 32 | pixel-format = "YUV420"; 33 | fps = -1.0; 34 | filters = ( 35 | # of course you can apply all kinds of filters 36 | # to the stream 37 | ); 38 | } 39 | } 40 | ) 41 | -------------------------------------------------------------------------------- /examples/lcdproc-overlay.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | # this code uses the 'lcdproc-python3' library: 4 | # https://github.com/jinglemansweep/lcdproc 5 | 6 | # for more details about lcdproc, see: 7 | # http://lcdproc.org/ 8 | 9 | from lcdproc.server import Server 10 | import time 11 | import urllib.request 12 | 13 | def main(): 14 | # 'localhost' must be replaced by the network address on which the 15 | # constatus server runs 16 | lcd = Server('localhost', debug=True) 17 | 18 | lcd.start_session() 19 | 20 | # you can have multiple screens. constatus will switch between them 21 | # every 4 seconds 22 | screen1 = lcd.add_screen('Screen1') 23 | 24 | # a screen can have multiple widgets 25 | screen1.add_string_widget('strwidget1', text='Bitcoin rate:', x=1, y=1) # widget1 26 | widget2 = screen1.add_string_widget('strwidget2', text='', x=1, y=2) 27 | 28 | while True: 29 | # retrieve bitcoin rate (don't depend on this: this service is often behind 30 | # for weeks) 31 | h = urllib.request.urlopen('https://vps001.vanheusden.com/btc/latest.txt') 32 | 33 | widget2.set_text(h.read().decode('utf-8')) 34 | 35 | time.sleep(30) 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /src/view_ss.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cfg.h" 8 | #include "view.h" 9 | 10 | class source; 11 | class target; 12 | 13 | class view_ss : public view 14 | { 15 | private: 16 | const bool auto_shrink; 17 | unsigned long event_nr { 0 }; 18 | 19 | protected: 20 | const double switch_interval; 21 | video_frame *prev_frame { nullptr }; 22 | 23 | size_t cur_source_index; 24 | uint64_t latest_switch; 25 | source *cur_source; 26 | 27 | public: 28 | view_ss(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const bool auto_shrink, const std::vector & sources, const double switch_interval, std::vector *const filters, const int jpeg_quality); 29 | virtual ~view_ss(); 30 | 31 | std::string get_html(const std::map & pars) const override; 32 | 33 | video_frame * get_frame(const bool handle_failure, const uint64_t after) override; 34 | 35 | virtual source *get_current_source() override; 36 | 37 | void start() override; 38 | void stop() override; 39 | 40 | virtual void operator()() override; 41 | }; 42 | -------------------------------------------------------------------------------- /src/source-plugins/Makefile: -------------------------------------------------------------------------------- 1 | # (C) 2017 by folkert van heusden, this file is released in the public domain 2 | INSTALL_PREFIX=/usr/local 3 | 4 | CFLAGS=-fPIC -Wall -pedantic -ggdb3 `pkg-config --cflags freetype2` 5 | CXXFLAGS=-fPIC -Wall -pedantic -ggdb3 -std=c++17 `pkg-config --cflags freetype2` 6 | VERSION=0.1 7 | 8 | OBJS1=demo.o 9 | OBJS2=vnc.o 10 | OBJS3=mqtt-images.o 11 | 12 | all: lib1 vnc mqtt-images 13 | 14 | lib1: $(OBJS1) 15 | ar -r demo.a $(OBJS1) 16 | ld -g -x -lm -shared -soname demo.so.2 -o demo.so.$(VERSION) --whole-archive demo.a 17 | 18 | vnc: $(OBJS2) 19 | ar -r vnc.a $(OBJS2) 20 | ld -g -x -lm -shared -soname vnc.so.2 -o vnc.so.$(VERSION) --whole-archive vnc.a 21 | 22 | mqtt-images: $(OBJS3) 23 | ar -r mqtt-images.a $(OBJS3) 24 | ld -g -x -lm `pkg-config --libs libmosquitto` -shared -soname mqtt-images.so.2 -o mqtt-images.so.$(VERSION) --whole-archive mqtt-images.a 25 | 26 | install: all 27 | cp demo.so.* vnc.so.* mqtt-images.so.* $(INSTALL_PREFIX)/lib 28 | /sbin/ldconfig 29 | 30 | uninstall: clean 31 | rm -f $(INSTALL_PREFIX)/lib/demo.so.* $(INSTALL_PREFIX)/lib/vnc.so.* $(INSTALL_PREFIX)/lib/mqtt-images.so.* 32 | 33 | clean: 34 | rm -f $(OBJS1) demo.a demo.so.* core $(OBJS2) vnc.a vnc.so.* mqtt-images.a mqtt-images.so.* $(OBJS3) 35 | -------------------------------------------------------------------------------- /src/target_pipewire.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | #if HAVE_PIPEWIRE == 1 5 | 6 | #include 7 | #include 8 | 9 | 10 | struct pmit_data 11 | { 12 | std::string id; 13 | 14 | pw_context *context { nullptr }; 15 | pw_main_loop *loop { nullptr }; 16 | pw_core *core { nullptr }; 17 | 18 | pw_stream *stream { nullptr }; 19 | spa_hook stream_listener; 20 | 21 | spa_video_info_raw format; 22 | int32_t stride { 0 }; 23 | 24 | uint32_t seq { 0 }; 25 | 26 | source *s { nullptr }; 27 | 28 | std::atomic_bool playing { false }; 29 | }; 30 | 31 | class target_pipewire : public target 32 | { 33 | private: 34 | const int quality; 35 | 36 | pmit_data data; 37 | 38 | std::atomic_bool playing { false }; 39 | 40 | public: 41 | target_pipewire(const std::string & id, const std::string & descr, source *const s, const double interval, const std::vector *const filters, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 42 | virtual ~target_pipewire(); 43 | 44 | void operator()() override; 45 | }; 46 | #endif 47 | -------------------------------------------------------------------------------- /src/target_avi.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_GSTREAMER == 1 5 | #include "target.h" 6 | #include 7 | #include 8 | 9 | class target_avi : public target 10 | { 11 | private: 12 | const int quality; 13 | 14 | std::string name; 15 | unsigned int f_nr { 0 }; 16 | bool is_start { true }; 17 | 18 | void put_frame(GstAppSrc *const appsrc, video_frame * const f); 19 | void open_file(const std::string & base_pipeline, GstElement **const gpipeline, GstAppSrc **const appsrc); 20 | void close_file(GstElement **const gpipeline, GstAppSrc **const appsrc); 21 | 22 | public: 23 | target_avi(const std::string & id, const std::string & descr, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int quality, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, const double override_fps, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 24 | virtual ~target_avi(); 25 | 26 | void operator()() override; 27 | }; 28 | #endif 29 | -------------------------------------------------------------------------------- /src/filter_add_bitmap.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "filter_add_text.h" 8 | #include "filter_add_bitmap.h" 9 | #include "error.h" 10 | #include "utils.h" 11 | 12 | filter_add_bitmap::filter_add_bitmap(const std::string & which, const int x, const int y) : which(which), x(x), y(y) 13 | { 14 | } 15 | 16 | filter_add_bitmap::~filter_add_bitmap() 17 | { 18 | } 19 | 20 | void filter_add_bitmap::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 21 | { 22 | int work_x = x < 0 ? x + w : x; 23 | int work_y = y < 0 ? y + h : y; 24 | 25 | std::pair it; 26 | 27 | if (specific_int->get_meta()->get_bitmap(which, &it)) { 28 | int putw = std::min(w - work_x, it.second->get_w()); 29 | int puth = std::min(h - work_y, it.second->get_h()); 30 | 31 | uint8_t *data = it.second->get_data(E_RGB); 32 | 33 | for(int puty=0; putyget_w() * 3], putw * 3); 35 | 36 | delete it.second; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/http_auth.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | 6 | #include "http_auth.h" 7 | #include "log.h" 8 | 9 | http_auth::http_auth(const std::string & auth_file) : auth_file(auth_file) 10 | { 11 | } 12 | 13 | http_auth::~http_auth() 14 | { 15 | } 16 | 17 | std::tuple http_auth::authenticate(const std::string & username, const std::string & password) 18 | { 19 | log(LL_INFO, "Authenticate user %s", username.c_str()); 20 | 21 | std::ifstream fh(auth_file); 22 | if (!fh.is_open()) 23 | return std::make_tuple(false, "Cannot open auth file"); 24 | 25 | std::string f_username, f_password; 26 | if (!getline(fh, f_username)) { 27 | fh.close(); 28 | return std::make_tuple(false, "Username missing in auth file"); 29 | } 30 | 31 | if (!getline(fh, f_password)) { 32 | fh.close(); 33 | return std::make_tuple(false, "Password missing in auth file"); 34 | } 35 | 36 | fh.close(); 37 | 38 | if (username != f_username) 39 | return std::make_tuple(false, "Username/password mismatch"); 40 | 41 | if (password != f_password) 42 | return std::make_tuple(false, "Username/password mismatch"); 43 | 44 | return std::make_tuple(true, "Ok"); 45 | } 46 | -------------------------------------------------------------------------------- /src/draw.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include 3 | #include "gen.h" 4 | 5 | void draw_horizonal(uint8_t *const target, const int tw, const int x, const int y, const int w, const rgb_t col) 6 | { 7 | int offset = y * tw * 3; 8 | 9 | for(int drawx=x; drawx 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "filter_median.h" 10 | #include "log.h" 11 | #include "utils.h" 12 | 13 | filter_median::filter_median(const size_t median_n) : median_n(median_n) 14 | { 15 | } 16 | 17 | filter_median::~filter_median() 18 | { 19 | for(auto p : h_frames) 20 | free(p); 21 | } 22 | 23 | void filter_median::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 24 | { 25 | if (h_frames.size() > median_n) { 26 | free(h_frames.at(0)); 27 | h_frames.erase(h_frames.begin()); 28 | } 29 | 30 | size_t n_bytes = IMS(w, h, 3); 31 | uint8_t *copy = (uint8_t *)duplicate(in_out, n_bytes); 32 | 33 | h_frames.push_back(copy); 34 | 35 | if (h_frames.size() < median_n) 36 | return; 37 | 38 | std::vector values; 39 | values.resize(median_n); 40 | 41 | for(size_t p=0; pjoin(); 18 | 19 | delete th; 20 | } 21 | 22 | void feed_exec::operator()() 23 | { 24 | set_thread_name("feed_exec"); 25 | 26 | while(!stop_flag) { 27 | uint64_t before_ts = get_us(); 28 | 29 | FILE *fh = exec(commandline); 30 | if (fh) { 31 | std::lock_guard lck(lock); 32 | 33 | latest_text.clear(); 34 | 35 | while(!feof(fh)) { 36 | char buffer[1024] = { 0 }; 37 | 38 | if (fgets(buffer, sizeof buffer, fh) == nullptr) 39 | break; 40 | 41 | latest_text += buffer; 42 | } 43 | 44 | pclose(fh); 45 | 46 | if (latest_text.empty() == false) { 47 | latest_ts = before_ts; 48 | 49 | cond.notify_all(); 50 | } 51 | } 52 | 53 | uint64_t after_ts = get_us(); 54 | 55 | int64_t sleep_duration = interval_ms * 1000 - (after_ts - before_ts); 56 | 57 | mysleep(sleep_duration, &stop_flag, nullptr); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/filter_copy.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "filter_copy.h" 10 | #include "log.h" 11 | #include "utils.h" 12 | 13 | filter_copy::filter_copy(const std::string & remember_as, const int x, const int y, const int w, const int h) : remember_as(remember_as), x(x), y(y), w(w), h(h) 14 | { 15 | } 16 | 17 | filter_copy::~filter_copy() 18 | { 19 | } 20 | 21 | void filter_copy::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 22 | { 23 | int work_x = this->x < 0 ? this->x + w : this->x; 24 | int work_y = this->y < 0 ? this->y + h : this->y; 25 | 26 | size_t n_bytes = IMS(this->w, this->h, 3); 27 | uint8_t *data = (uint8_t *)malloc(n_bytes); 28 | 29 | for(int y=0; yh; y++) 30 | memcpy(&data[y * this->w * 3], &in_out[(work_y + y) * w * 3 + work_x * 3], this->w * 3); 31 | 32 | meta *const m = specific_int->get_meta(); 33 | 34 | video_frame *vf = new video_frame(m, 100, ts, this->w, this->h, data, n_bytes, E_RGB); 35 | 36 | m -> set_bitmap(remember_as, std::pair(0, vf)); 37 | } 38 | -------------------------------------------------------------------------------- /src/filter_apply_mask.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "gen.h" 8 | #include "filter_apply_mask.h" 9 | #include "selection_mask.h" 10 | 11 | filter_apply_mask::filter_apply_mask(selection_mask *const pixel_select_bitmap, const bool soft_mask) : psb(pixel_select_bitmap), soft_mask(soft_mask) 12 | { 13 | } 14 | 15 | filter_apply_mask::~filter_apply_mask() 16 | { 17 | delete psb; 18 | } 19 | 20 | void filter_apply_mask::apply(instance *const inst, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 21 | { 22 | const uint8_t *const sb = psb -> get_mask(w, h); 23 | 24 | if (soft_mask) { 25 | int tr = 0, tg = 0, tb = 0, tn = 0; 26 | 27 | for(int i=0, o=0; i 4 | 5 | #include "filter.h" 6 | 7 | void *find_symbol(void *const dl, const std::string & filename, const std::string & function, const bool is_fatal=true); 8 | void *load_library(const std::string & filename); 9 | 10 | typedef void * (*init_filter_t)(const char *const par); 11 | typedef void (*apply_filter_t)(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result); 12 | typedef void (*uninit_filter_t)(void *arg); 13 | 14 | class filter_plugin : public filter 15 | { 16 | private: 17 | init_filter_t init_filter { nullptr }; 18 | apply_filter_t apply_filter { nullptr }; 19 | uninit_filter_t uninit_filter { nullptr }; 20 | 21 | protected: 22 | void *library { nullptr }; 23 | void *arg { nullptr }; 24 | 25 | filter_plugin() { } 26 | 27 | public: 28 | filter_plugin(const std::string & filter_filename, const std::string & parameter); 29 | ~filter_plugin(); 30 | 31 | virtual bool uses_in_out() const override { return true; } 32 | virtual void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 33 | }; 34 | -------------------------------------------------------------------------------- /src/motion_trigger.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #include 5 | #if HAVE_JANSSON == 1 6 | #include 7 | #endif 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "interface.h" 14 | 15 | class filter; 16 | class parameter; 17 | class schedule; 18 | class selection_mask; 19 | class source; 20 | class target; 21 | 22 | class motion_trigger : public interface 23 | { 24 | protected: 25 | std::map parameters; 26 | 27 | std::vector event_clients; 28 | 29 | std::vector *const targets; 30 | 31 | schedule *const sched; 32 | 33 | public: 34 | motion_trigger(const std::string & id, const std::string & descr, const std::map & detection_parameters, std::vector *const targets, schedule *const sched); 35 | virtual ~motion_trigger(); 36 | 37 | virtual bool check_motion() { return false; } 38 | 39 | #if HAVE_JANSSON == 1 40 | json_t * get_rest_parameters(); 41 | json_t * rest_set_parameter(const std::string & key, const std::string & value); 42 | #endif 43 | 44 | void register_notifier(interface *const i); 45 | void unregister_notifier(interface *const i); 46 | 47 | virtual void operator()() override; 48 | }; 49 | -------------------------------------------------------------------------------- /src/ws_server_tls.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_WEBSOCKETPP == 1 5 | #include "webservices.h" 6 | #include "ws_server.h" 7 | 8 | #include 9 | #include 10 | 11 | typedef websocketpp::server server_tls; 12 | 13 | using websocketpp::connection_hdl; 14 | using websocketpp::lib::placeholders::_1; 15 | using websocketpp::lib::placeholders::_2; 16 | using websocketpp::lib::bind; 17 | 18 | class ws_server_tls : public ws_server 19 | { 20 | private: 21 | server_tls m_server_tls; 22 | const ssl_pars_t sp; 23 | 24 | public: 25 | ws_server_tls(configuration_t *const cfg, const std::string & id, const std::string & descr, const listen_adapter_t & la, http_server *const hs, const ssl_pars_t & sp, const bool use_auth, http_cookies *const c); 26 | virtual ~ws_server_tls(); 27 | 28 | virtual void push(const std::string & msg, const std::string & cache_under) override; 29 | 30 | bool on_validate(connection_hdl hdl) override; 31 | 32 | std::string address_from_hdl(connection_hdl hdl) override; 33 | 34 | void ws_stop() override; 35 | 36 | void operator()() override; 37 | 38 | websocketpp::lib::shared_ptr on_tls_init(websocketpp::connection_hdl); 39 | }; 40 | #endif 41 | -------------------------------------------------------------------------------- /src/source_pipewire.h: -------------------------------------------------------------------------------- 1 | // (c) 2017-2021 by folkert van heusden, released under agpl v3.0 2 | #pragma once 3 | 4 | #include "config.h" 5 | #include 6 | #include 7 | #include 8 | #if HAVE_PIPEWIRE == 1 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "source.h" 16 | #include "picio.h" 17 | 18 | struct pmis_data 19 | { 20 | struct pw_main_loop *loop; 21 | struct pw_stream *stream; 22 | 23 | struct spa_video_info format; 24 | 25 | source *s; 26 | 27 | transformer_t tf; 28 | }; 29 | 30 | class source_pipewire : public source 31 | { 32 | private: 33 | const int source_id; 34 | const double interval; 35 | 36 | struct pmis_data data { 0, }; 37 | const struct spa_pod *params[1] { nullptr }; 38 | struct spa_rectangle min_dim, default_dim, max_dim; 39 | struct spa_fraction min_frac, default_frac, max_frac; 40 | 41 | public: 42 | source_pipewire(const std::string & id, const std::string & descr, const int source_id, const int width, const int height, const int quality, controls *const c, const double max_fps, const std::map & text_feeds, const bool keep_aspectratio); 43 | ~source_pipewire(); 44 | 45 | void operator()() override; 46 | }; 47 | #endif 48 | -------------------------------------------------------------------------------- /src/stats_tracker.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class stats_tracker 12 | { 13 | private: 14 | const std::string id; 15 | const bool is_global; 16 | 17 | int prev_slot_ru { -1 }; 18 | uint64_t prev_ru_ts { 0 }, latest_ru_ts { 0 }; 19 | struct rusage latest_ru { 0 }, prev_ru { 0 }; 20 | double cpu_stats[5] { 0. }; 21 | 22 | int fps_counts[5]{ 0 }, last_fps_count_sec{ 0 }; 23 | bool fps_set[5] { false }; 24 | 25 | int bw_counts[5]{ 0 }, last_bw_count_sec{ 0 }; 26 | int cc_counts[5]{ 0 }, last_cc_count_sec{ 0 }; 27 | 28 | std::thread *th { nullptr }; 29 | 30 | std::condition_variable cv_stop; 31 | mutable std::mutex m; 32 | bool cv_stop_notify { false }; 33 | 34 | public: 35 | stats_tracker(const std::string & id, const bool is_global); 36 | virtual ~stats_tracker(); 37 | 38 | void start(); 39 | void operator()(); 40 | 41 | void track_cpu_usage(); 42 | double get_cpu_usage() const; 43 | void reset_cpu_tracking(); 44 | 45 | void track_fps(); 46 | virtual std::optional get_fps() const; 47 | 48 | void track_bw(const int bytes); 49 | virtual int get_bw() const; 50 | 51 | void track_cc(const int count); 52 | virtual double get_cc() const; 53 | }; 54 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | extraction: 2 | cpp: 3 | prepare: 4 | packages: 5 | - libconfig++-dev 6 | - libfontconfig1-dev 7 | - libfreetype6-dev 8 | - libicu-dev 9 | - libturbojpeg0-dev 10 | - libpng-dev 11 | - libcurl4-openssl-dev 12 | - libjansson-dev 13 | - libssl-dev 14 | - libboost-system-dev 15 | - build-essential 16 | - cmake 17 | - pkg-config 18 | - libv4l-dev 19 | - libexiv2-dev 20 | - libmysqlcppconn-dev 21 | - frei0r-plugins-dev 22 | - libpam0g-dev 23 | - libgstreamer1.0-dev 24 | - libgstreamer-plugins-base1.0-dev 25 | - libwebsocketpp-dev 26 | - libsdl2-dev 27 | - rygel 28 | - rygel-2.6-dev 29 | - libglib2.0-dev 30 | - libxml2-dev 31 | - libgee-0.8-dev 32 | - libgupnp-av-1.0-dev 33 | - libupnp-dev 34 | - libasound2-dev 35 | - libmagick++-dev 36 | - libavformat-dev 37 | - libswscale-dev 38 | - libavcodec-dev 39 | - libavutil-dev 40 | - libswresample-dev 41 | - libavresample-dev 42 | - libatomic1 43 | configure: 44 | command: 45 | - mkdir _lgtm_build_dir 46 | - cd _lgtm_build_dir 47 | - cmake -DLGTM=1 .. 48 | index: 49 | build_command: 50 | - cd _lgtm_build_dir 51 | - make 52 | -------------------------------------------------------------------------------- /src/view.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | 6 | #include "cfg.h" 7 | #include "source.h" 8 | #include "gen.h" 9 | 10 | typedef struct { 11 | std::string id; 12 | pos_t pos; // currently only for PIP views 13 | int perc; // shrink percentage (PIP views) 14 | } view_src_t; 15 | 16 | class view : public source 17 | { 18 | protected: 19 | configuration_t *const cfg; 20 | const std::vector sources; 21 | 22 | public: 23 | view(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, std::vector *const filters, const int jpeg_quality); 24 | view(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, const int jpeg_quality); 25 | virtual ~view(); 26 | 27 | virtual std::string get_html(const std::map & pars) const = 0; 28 | 29 | virtual video_frame * get_frame(const bool handle_failure, const uint64_t after) override { return { }; } 30 | 31 | virtual source *get_current_source(); 32 | 33 | const std::vector get_sources() const { return sources; } 34 | 35 | std::optional get_fps() override; 36 | 37 | virtual void operator()() override; 38 | }; 39 | -------------------------------------------------------------------------------- /src/source_v4l.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_LIBV4L2 == 1 5 | #include 6 | #include 7 | #include 8 | 9 | #include "source.h" 10 | 11 | class source_v4l : public source 12 | { 13 | protected: 14 | const std::string dev; 15 | const int w_override, h_override; 16 | const int use_controls; 17 | int fd, vw, vh; 18 | unsigned int pixelformat; 19 | 20 | struct buffer { 21 | void *start; 22 | size_t length; 23 | }; 24 | 25 | struct buffer *buffers = nullptr; 26 | int n_buffers; 27 | 28 | const bool prefer_jpeg { false }; 29 | 30 | public: 31 | source_v4l(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & dev, const int jpeg_quality, const double max_fps, const int w_override, const int h_override, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, const bool prefer_jpeg, const bool use_controls, const std::map & text_feeds, const bool keep_aspectratio); 32 | virtual ~source_v4l(); 33 | 34 | virtual void pan_tilt(const double abs_pan, const double abs_tilt) override; 35 | virtual void get_pan_tilt(double *const pan, double *const tilt) const override; 36 | 37 | virtual void operator()() override; 38 | }; 39 | #endif 40 | -------------------------------------------------------------------------------- /src/filter_plugin_frei0r.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_FREI0R == 1 5 | #include 6 | #include 7 | 8 | #include "filter_plugin.h" 9 | 10 | typedef void (*my_f0r_update)(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe); 11 | typedef void (*my_f0r_update2_3)(f0r_instance_t instance, double time, const uint32_t* inframe1, const uint32_t* inframe2, const uint32_t* inframe3, uint32_t* outframe); 12 | ; 13 | 14 | class filter_plugin_frei0r : public filter_plugin 15 | { 16 | private: 17 | const std::string filter_filename, pars; 18 | const std::vector other_sources; 19 | resize *const r; 20 | 21 | my_f0r_update my_f0r_update_i{ nullptr }; 22 | my_f0r_update2_3 my_f0r_update_i_2_3{ nullptr }; 23 | f0r_instance_t f_inst{ nullptr }; 24 | int color_model{ -1 }; 25 | int plugin_type{ 0 }; 26 | f0r_plugin_info_t fpi{ 0 }; 27 | 28 | public: 29 | filter_plugin_frei0r(const std::string & filter_filename, const std::string & pars, const std::vector & other_sources, resize *const r); 30 | ~filter_plugin_frei0r(); 31 | 32 | bool uses_in_out() const override { return true; } 33 | void apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) override; 34 | }; 35 | #endif 36 | -------------------------------------------------------------------------------- /src/filter-plugins/keep-alive.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2024 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "cairo.h" 11 | #include "../utils.h" 12 | 13 | extern "C" { 14 | void * init_filter(const char *const parameter) 15 | { 16 | return new uint64_t(); 17 | } 18 | 19 | void apply_filter(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result) 20 | { 21 | uint32_t *temp = NULL; 22 | cairo_surface_t *const cs = rgb_to_cairo(current_frame, w, h, &temp); 23 | cairo_t *const cr = cairo_create(cs); 24 | 25 | uint64_t t_diff = ts - *reinterpret_cast(arg); 26 | if (t_diff >= 500000) { 27 | int r = std::min(w, h) / 20; // 5% 28 | /// 29 | cairo_set_source_rgb(cr, 0.6, 0.8, 1.0); 30 | cairo_move_to(cr, r * 1.5, r * 1.5); 31 | cairo_arc(cr, r * 1.5, r * 1.5, r, 0.0, 2 * M_PI); 32 | cairo_fill(cr); 33 | cairo_stroke(cr); 34 | /// 35 | if (t_diff >= 1000000) 36 | *reinterpret_cast(arg) = ts; 37 | } 38 | 39 | cairo_to_rgb(cs, w, h, result); 40 | 41 | cairo_destroy(cr); 42 | cairo_surface_destroy(cs); 43 | free(temp); 44 | } 45 | 46 | void uninit_filter(void *arg) 47 | { 48 | delete reinterpret_cast(arg); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: constatus 2 | Maintainer: Folkert van Heusden 3 | Section: graphics 4 | Priority: optional 5 | Standards-Version: 4.5.0 6 | Build-Depends: debhelper-compat (= 12), 7 | libboost-system-dev, 8 | libconfig++-dev, 9 | libfontconfig1-dev, 10 | libfreetype6-dev, 11 | libicu-dev, 12 | libturbojpeg0-dev, 13 | libpng-dev, 14 | libcurl4-openssl-dev, 15 | libjansson-dev, 16 | libssl-dev, 17 | cmake, 18 | pkg-config, 19 | libtheora-dev, 20 | libcamera-dev, 21 | libv4l-dev, 22 | libnetpbm10-dev, 23 | libexiv2-dev, 24 | libmysqlcppconn-dev, 25 | frei0r-plugins-dev, 26 | libpam0g-dev, 27 | libgstreamer1.0-dev, 28 | libgstreamer-plugins-base1.0-dev, 29 | libwebsocketpp-dev, 30 | libsdl2-dev, 31 | rygel, 32 | rygel-2.8-dev, 33 | libglib2.0-dev, 34 | libxml2-dev, 35 | libgee-0.8-dev, 36 | libgupnp-av-1.0-dev, 37 | libupnp-dev, 38 | libasound2-dev, 39 | libmagick++-dev, 40 | libavformat-dev, 41 | libswscale-dev, 42 | libavcodec-dev, 43 | libavutil-dev, 44 | libswresample-dev, 45 | libatomic1, 46 | libpipewire-0.3-dev, 47 | libspa-0.2-dev, 48 | libmosquitto-dev 49 | Homepage: https://www.vanheusden.com/constatus/ 50 | 51 | Package: constatus 52 | Architecture: any 53 | Depends: ${shlibs:Depends}, ${misc:Depends} 54 | Description: Video monitoring and streaming program. 55 | It can detect motion, act on that. It can filter, 56 | merge streams, write to disk, send to v4l2- 57 | loopback, has an internal webserver and plugin 58 | interfaces. 59 | -------------------------------------------------------------------------------- /src/filter_marker_simple.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "filter.h" 7 | 8 | class selection_mask; 9 | 10 | typedef enum { m_red, m_red_invert, m_invert, m_color } sm_mode_t; 11 | 12 | typedef struct { 13 | sm_mode_t mode; 14 | uint8_t r, g, b; 15 | } sm_pixel_t; 16 | 17 | typedef enum { t_box, t_cross, t_circle, t_border } sm_type_t; 18 | 19 | void update_pixel(uint8_t *const out, const int x, const int y, const int w); 20 | 21 | class filter_marker_simple : public filter 22 | { 23 | private: 24 | const sm_pixel_t pixel; 25 | const sm_type_t type; 26 | selection_mask *const pixel_select_bitmap; 27 | const int noise_level; 28 | const double percentage_pixels_changed; 29 | const int thick; 30 | instance *const i; 31 | const bool store_motion_bitmap; 32 | 33 | std::atomic_bool changed { false }; 34 | 35 | public: 36 | filter_marker_simple(instance *const i, const sm_pixel_t pixel, const sm_type_t type, selection_mask *const sb, const int noise_level, const double percentage_pixels_changed, const int thick, const bool store_motion_bitmap); 37 | virtual ~filter_marker_simple(); 38 | 39 | void notify_thread_of_event(const std::string & subject) override; 40 | 41 | bool uses_in_out() const override { return false; } 42 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 43 | }; 44 | -------------------------------------------------------------------------------- /src/picio.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "gen.h" 4 | #include 5 | #include 6 | #include 7 | 8 | class meta; 9 | 10 | bool read_PNG_file_rgba(bool with_alpha, FILE *fh, int *w, int *h, uint8_t **pixels); 11 | void write_PNG_file(FILE *fh, int ncols, int nrows, unsigned char *pixels); 12 | 13 | void load_PBM_file(FILE *const fh, int *const w, int *const h, uint8_t **out); 14 | 15 | #define transformer_t tjhandle 16 | 17 | class myjpeg 18 | { 19 | private: 20 | tjhandle jpegDecompressor, jpegCompressor; 21 | 22 | public: 23 | myjpeg(); 24 | virtual ~myjpeg(); 25 | 26 | bool write_JPEG_memory(const meta *const m, const int ncols, const int nrows, const int quality, const uint8_t *const pixels, uint8_t **out, size_t *out_len); 27 | bool read_JPEG_memory(unsigned char *in, int n_bytes_in, int *w, int *h, unsigned char **pixels); 28 | 29 | static void rgb_to_i420(transformer_t t, const uint8_t *const in, const int width, const int height, uint8_t **const out, uint8_t **const y = nullptr, uint8_t **const u = nullptr, uint8_t **const v = nullptr, const bool swap_rgb = false); 30 | static void i420_to_rgb(transformer_t t, const uint8_t *const in, const int width, const int height, uint8_t **const out); 31 | static transformer_t allocate_transformer(); 32 | static void free_transformer(transformer_t h); 33 | }; 34 | 35 | extern thread_local myjpeg my_jpeg; 36 | 37 | bool read_bmp(unsigned char *in, int n_bytes_in, int *w, int *h, unsigned char **pixels); 38 | -------------------------------------------------------------------------------- /src/motiontrigger-plugins/demo.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | 8 | void * init_motion_trigger(const char *const parameter) 9 | { 10 | // you can use the parameter for anything you want 11 | // e.g. the filename of a configuration file or 12 | // maybe a variable or whatever 13 | 14 | // what you return here, will be given as a parameter 15 | // to detect_motion 16 | 17 | return NULL; 18 | } 19 | 20 | // ts is current timestamp in microseconds 21 | // w,h are the dimensions of the pixel-data in prev_frame and current_frame 22 | // (both are RGB data, so 3 bytes per pixel) 23 | // selection_bitmap is a bitmap informing which pixels to look at and which 24 | // too ignore 25 | // meta can contain a pointer to a text-string with meta data. e.g. when a 26 | // moving object is recognized, you can add a pointer to a free()-able text 27 | // in it. you can then print it in-line in the video-feed via a text-filter: 28 | // { 29 | // type = "text"; 30 | // text = "$motion-meta$"; 31 | // position = "lower-right" 32 | // } 33 | // '$motion-meta$' will be replaced by the text in *meta. 34 | 35 | bool detect_motion(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, uint8_t *const current_frame, const uint8_t *const pixel_selection_bitmap, char **const meta) 36 | { 37 | return false; 38 | } 39 | 40 | void uninit_motion_trigger(void *arg) 41 | { 42 | // free memory etc 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/view_html_all.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include "gen.h" 5 | #include "view_html_all.h" 6 | #include "http_server.h" 7 | #include "instance.h" 8 | #include "utils.h" 9 | 10 | view_html_all::view_html_all(configuration_t *const cfg, const std::string & id, const std::string & descr, const std::vector & sources, const int jpeg_quality) : view(cfg, id, descr, -1, -1, sources, jpeg_quality) 11 | { 12 | } 13 | 14 | view_html_all::~view_html_all() 15 | { 16 | } 17 | 18 | std::string view_html_all::get_html(const std::map & pars) const 19 | { 20 | std::string reply = "" 21 | "" 22 | "" 23 | "" NAME " " VERSION "" 24 | "" 25 | "
"; 26 | 27 | for(instance * inst : cfg -> instances) { 28 | source *const s = find_source(inst); 29 | 30 | if (!s || s -> get_class_type() == CT_VIEW) 31 | continue; 32 | 33 | int w = s -> get_width(); 34 | int use_h = s -> get_height() * (320.0 / w); 35 | 36 | reply += myformat("", url_escape(inst -> name).c_str(), inst -> name.c_str(), url_escape(inst -> name).c_str(), use_h); 37 | } 38 | 39 | reply += "
"; 40 | 41 | return reply; 42 | } 43 | 44 | void view_html_all::operator()() 45 | { 46 | } 47 | -------------------------------------------------------------------------------- /src/filter_chromakey.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "error.h" 9 | #include "gen.h" 10 | #include "filter_chromakey.h" 11 | #include "picio.h" 12 | #include "utils.h" 13 | #include "source.h" 14 | #include "resize.h" 15 | 16 | filter_chromakey::filter_chromakey(source *const cks, resize *const r) : cks(cks), r(r) 17 | { 18 | cks->start(); 19 | } 20 | 21 | filter_chromakey::~filter_chromakey() 22 | { 23 | // at this point (shutdown) the cks no longer exists 24 | // cks->stop(); 25 | } 26 | 27 | void filter_chromakey::apply(instance *const inst, interface *const specific_int, const uint64_t ts, const int width, const int height, const uint8_t *const prev, uint8_t *const in_out) 28 | { 29 | video_frame *pvf = cks-> get_frame(true, ts); 30 | if (!pvf) 31 | return; 32 | 33 | if (pvf->get_w() != width || pvf->get_h() != height) { 34 | video_frame *temp = pvf->do_resize(r, width, height); 35 | delete pvf; 36 | pvf = temp; 37 | } 38 | 39 | 40 | // if pixel in `in_out' == green, 41 | // replace by cks frame 42 | 43 | const uint8_t *const in = pvf->get_data(E_RGB); 44 | 45 | for(int i=0; i= 90 && h < 150 && l >= 0.2) { 52 | in_out[i3 + 0] = in[i3 + 0]; 53 | in_out[i3 + 1] = in[i3 + 1]; 54 | in_out[i3 + 2] = in[i3 + 2]; 55 | } 56 | } 57 | 58 | delete pvf; 59 | } 60 | -------------------------------------------------------------------------------- /src/filter-plugins/demoocv2.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern "C" { 12 | 13 | void * init_filter(const char *const parameter) 14 | { 15 | cv::CascadeClassifier *face_cascade = new cv::CascadeClassifier(); 16 | if (!face_cascade -> load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml")) 17 | printf("load failed\n"); 18 | 19 | return face_cascade; 20 | } 21 | 22 | void apply_filter(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result) 23 | { 24 | cv::CascadeClassifier *face_cascade = (cv::CascadeClassifier *)arg; 25 | 26 | cv::Mat frame = cv::Mat(h, w, CV_8UC3, (void *)current_frame); 27 | 28 | cv::Mat frame_gray; 29 | cv::cvtColor(frame, frame_gray, cv::COLOR_BGR2GRAY); 30 | cv::equalizeHist(frame_gray, frame_gray); 31 | 32 | std::vector faces; 33 | face_cascade -> detectMultiScale(frame_gray, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30)); 34 | 35 | for(size_t i = 0; i < faces.size(); i++) 36 | cv::rectangle(frame, faces[i].tl(), faces[i].br(), cv::Scalar(0, 0, 255), 2, 8, 0); 37 | 38 | memcpy(result, frame.data, w * h * 3); 39 | 40 | frame_gray.release(); 41 | frame.release(); 42 | } 43 | 44 | void uninit_filter(void *arg) 45 | { 46 | delete (cv::CascadeClassifier *)arg; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/http_auth_pam.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #if HAVE_LIBPAM == 1 4 | #include 5 | #include 6 | 7 | #include "http_auth_pam.h" 8 | #include "log.h" 9 | 10 | int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) 11 | { 12 | pam_response *reply = (pam_response *)appdata_ptr; 13 | 14 | *resp = reply; 15 | 16 | return PAM_SUCCESS; 17 | } 18 | 19 | http_auth_pam::http_auth_pam() 20 | { 21 | } 22 | 23 | http_auth_pam::~http_auth_pam() 24 | { 25 | } 26 | 27 | std::tuple http_auth_pam::authenticate(const std::string & username, const std::string & password) 28 | { 29 | log(LL_INFO, "Authenticate user %s", username.c_str()); 30 | 31 | struct pam_response *reply = (struct pam_response *)malloc(sizeof(struct pam_response)); 32 | reply->resp = strdup(password.c_str()); 33 | reply->resp_retcode = 0; 34 | 35 | const struct pam_conv local_conversation { function_conversation, reply }; 36 | 37 | pam_handle_t *local_auth_handle = nullptr; 38 | if (pam_start("common-auth", username.c_str(), &local_conversation, &local_auth_handle) != PAM_SUCCESS) { 39 | free(reply); 40 | return std::make_tuple(false, "PAM error"); 41 | } 42 | 43 | int rc = pam_authenticate(local_auth_handle, PAM_SILENT); 44 | pam_end(local_auth_handle, rc); 45 | 46 | if (rc == PAM_AUTH_ERR) 47 | return std::make_tuple(false, "Authentication failed"); 48 | 49 | if (rc != PAM_SUCCESS) 50 | return std::make_tuple(false, "PAM error"); 51 | 52 | return std::make_tuple(true, "Ok"); 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /src/target_plugin.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "target.h" 4 | 5 | typedef void *(* tp_init_plugin_t)(const char *const argument); 6 | typedef void (* open_file_t)(void *arg, const char *const fname_prefix, const double fps, const int quality); 7 | typedef void (* write_frame_t)(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame); 8 | typedef void (* close_file_t)(void *arg); 9 | typedef void (* tp_uninit_plugin_t)(void *arg); 10 | 11 | typedef struct { 12 | std::string par; 13 | 14 | tp_init_plugin_t init_plugin; 15 | open_file_t open_file; 16 | write_frame_t write_frame; 17 | close_file_t close_file; 18 | tp_uninit_plugin_t uninit_plugin; 19 | 20 | void *arg; 21 | } stream_plugin_t; 22 | 23 | class target_plugin : public target 24 | { 25 | private: 26 | const int quality; 27 | stream_plugin_t *sp { nullptr }; 28 | bool is_start { true }; 29 | bool is_open { false }; 30 | 31 | void open_plugin(); 32 | 33 | public: 34 | target_plugin(const std::string & id, const std::string & descr, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int quality, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, stream_plugin_t *const sp, const double override_fps, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 35 | virtual ~target_plugin(); 36 | 37 | void operator()() override; 38 | }; 39 | -------------------------------------------------------------------------------- /src/filter_add_scaled_text.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "filter_add_text.h" 10 | #include "filter_add_scaled_text.h" 11 | #include "error.h" 12 | #include "utils.h" 13 | #include "draw_text.h" 14 | 15 | filter_add_scaled_text::filter_add_scaled_text(const std::string & what, const std::string & font_file, const int x, const int y, const int font_size, const int width, const std::optional bg, const rgb_t col, const bool invert, const std::map & text_feeds) : 16 | what(what), 17 | x(x), y(y), 18 | font_size(font_size), width(width), 19 | bg(bg), col(col), 20 | invert(invert), 21 | text_feeds(text_feeds) 22 | { 23 | font = new draw_text(font_file, font_size); 24 | } 25 | 26 | filter_add_scaled_text::~filter_add_scaled_text() 27 | { 28 | delete font; 29 | } 30 | 31 | void filter_add_scaled_text::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 32 | { 33 | std::string text_out = unescape(what, ts, i, specific_int, text_feeds); 34 | 35 | std::vector *parts; 36 | if (text_out.find("\n") != std::string::npos) 37 | parts = split(text_out.c_str(), "\n"); 38 | else 39 | parts = split(text_out.c_str(), "\\n"); 40 | 41 | int work_x = x < 0 ? x + w : x; 42 | int work_y = y < 0 ? y + h : y; 43 | 44 | for(std::string cl : *parts) { 45 | draw_text_on_bitmap(font, cl, w, h, in_out, font_size, col, bg, work_x, work_y); 46 | 47 | work_y += font_size + 1; 48 | } 49 | 50 | delete parts; 51 | } 52 | -------------------------------------------------------------------------------- /src/filter_plugin.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | 6 | #include "gen.h" 7 | #include "error.h" 8 | #include "filter_plugin.h" 9 | 10 | void *find_symbol(void *const dl, const std::string & filename, const std::string & function, const bool is_fatal) 11 | { 12 | void *sym = dlsym(dl, function.c_str()); 13 | if (!sym && is_fatal) 14 | error_exit(true, "Failed finding filter plugin \"%s\" in %s", function.c_str(), filename.c_str()); 15 | 16 | return sym; 17 | } 18 | 19 | void *load_library(const std::string & filename) 20 | { 21 | void *library = dlopen(filename.c_str(), RTLD_NOW); 22 | if (!library) 23 | error_exit(true, "Failed opening filter plugin library %s: %s", filename.c_str(), dlerror()); 24 | 25 | return library; 26 | } 27 | 28 | filter_plugin::filter_plugin(const std::string & filter_filename, const std::string & parameter) 29 | { 30 | library = load_library(filter_filename.c_str()); 31 | 32 | init_filter = (init_filter_t)find_symbol(library, filter_filename, "init_filter"); 33 | 34 | apply_filter = (apply_filter_t)find_symbol(library, filter_filename, "apply_filter"); 35 | 36 | uninit_filter = (uninit_filter_t)find_symbol(library, filter_filename, "uninit_filter"); 37 | 38 | arg = init_filter(parameter.c_str()); 39 | } 40 | 41 | filter_plugin::~filter_plugin() 42 | { 43 | if (arg) 44 | uninit_filter(arg); 45 | 46 | dlclose(library); 47 | } 48 | 49 | void filter_plugin::apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) 50 | { 51 | apply_filter(arg, ts, w, h, prev, in, out); 52 | } 53 | -------------------------------------------------------------------------------- /src/view.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include "gen.h" 5 | #include "view.h" 6 | #include "http_server.h" 7 | #include "utils.h" 8 | #include "controls.h" 9 | 10 | view::view(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, std::vector *const filters, const int jpeg_quality) : source(id, descr, "", width, height, cfg->r, filters, new controls(), jpeg_quality, cfg->text_feeds, false), cfg(cfg), sources(sources) 11 | { 12 | ct = CT_VIEW; 13 | } 14 | 15 | view::view(configuration_t *const cfg, const std::string & id, const std::string & descr, const int width, const int height, const std::vector & sources, const int jpeg_quality) : source(id, descr, "", width, height, cfg->r, new controls(), jpeg_quality, cfg->text_feeds, false), cfg(cfg), sources(sources) 16 | { 17 | ct = CT_VIEW; 18 | } 19 | 20 | view::~view() 21 | { 22 | delete c; 23 | } 24 | 25 | void view::operator()() 26 | { 27 | } 28 | 29 | source *view::get_current_source() 30 | { 31 | return this; 32 | } 33 | 34 | std::optional view::get_fps() 35 | { 36 | double tfps = 0.; 37 | int nfps = 0; 38 | 39 | for(size_t i=0; iget_fps(); 46 | 47 | if (fps.has_value()) { 48 | tfps+= fps.value(); 49 | nfps++; 50 | } 51 | } 52 | } 53 | 54 | if (nfps) 55 | return tfps / nfps; 56 | 57 | return { }; 58 | } 59 | -------------------------------------------------------------------------------- /src/source_static.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "error.h" 8 | #include "http_client.h" 9 | #include "source.h" 10 | #include "source_static.h" 11 | #include "filter_add_text.h" 12 | #include "picio.h" 13 | #include "filter.h" 14 | #include "log.h" 15 | #include "utils.h" 16 | #include "controls.h" 17 | 18 | source_static::source_static(const std::string & id, const std::string & descr, const int width, const int height, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio) : source(id, descr, "", width, height, nullptr, c, jpeg_quality, text_feeds, keep_aspectratio) 19 | { 20 | } 21 | 22 | source_static::~source_static() 23 | { 24 | delete c; 25 | } 26 | 27 | void source_static::operator()() 28 | { 29 | } 30 | 31 | video_frame * source_static::get_frame(const bool handle_failure, const uint64_t after) 32 | { 33 | size_t len = IMS(this->width, this->height, 3); 34 | uint8_t *p = (uint8_t *)malloc(len); 35 | 36 | struct timespec tv; 37 | clock_gettime(CLOCK_REALTIME, &tv); 38 | uint64_t ts = uint64_t(tv.tv_sec) * uint64_t(1000 * 1000) + uint64_t(tv.tv_nsec / 1000); 39 | 40 | memset(p, 0x20, len); 41 | 42 | filter_add_text fat1("Hello, world!", { center_center, -1, -1 }, text_feeds); 43 | fat1.apply(nullptr, this, ts, this->width, this->height, nullptr, p); 44 | 45 | filter_add_text fat2("%c", { upper_center, -1, -1 }, text_feeds); 46 | fat2.apply(nullptr, this, ts, this->width, this->height, nullptr, p); 47 | 48 | return new video_frame(get_meta(), jpeg_quality, ts, this->width, this->height, p, len, E_RGB); 49 | } 50 | -------------------------------------------------------------------------------- /src/filter_scroll.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "draw_text.h" 8 | #include "filter.h" 9 | #include "cfg.h" 10 | 11 | typedef struct 12 | { 13 | std::string text; 14 | uint8_t *bitmap; 15 | int w, h; 16 | } scroll_entry_t; 17 | 18 | class filter_scroll : public filter 19 | { 20 | protected: 21 | std::string what; 22 | draw_text *font { nullptr }; 23 | const int x, y, text_w, n_lines, font_size; 24 | const bool horizontal_scroll; 25 | const std::optional bg; 26 | const rgb_t col; 27 | const bool invert; 28 | const std::map text_feeds; 29 | 30 | std::mutex buffer_lock; 31 | std::vector buffer; 32 | 33 | std::atomic_bool local_stop_flag{ false }; 34 | 35 | size_t char_nr { 0 }; 36 | 37 | private: 38 | const std::string exec_what; 39 | const int scroll_speed; 40 | int fd { -1 }, cur_x_pos { 0 }; 41 | std::string in_buffer; 42 | 43 | void restart_process(); 44 | 45 | public: 46 | filter_scroll(const std::string & font_file, const int x, const int y, const int text_w, const int n_lines, const int font_size, const std::string & exec_what, const bool horizontal_scroll, const std::optional bg, const int scroll_speed, const rgb_t col, const bool invert, const std::map & text_feeds); 47 | ~filter_scroll(); 48 | 49 | bool uses_in_out() const override { return false; } 50 | void apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) override; 51 | 52 | virtual std::tuple poll_for_data(); 53 | 54 | void operator()() override; 55 | }; 56 | -------------------------------------------------------------------------------- /src/cleaner.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "cleaner.h" 11 | #include "utils.h" 12 | #include "error.h" 13 | #include "log.h" 14 | #include "db.h" 15 | #include "exec.h" 16 | 17 | cleaner::cleaner(const std::string & db_url, const std::string & db_user, const std::string & db_pass, const int check_interval, const int purge_interval, const int cookies_max_age) : interface("cleaner", "maintenance"), th(nullptr), local_stop_flag(false), check_interval(check_interval), purge_interval(purge_interval), cookies_max_age(cookies_max_age) 18 | { 19 | dbi = new db(db_url, db_user, db_pass); 20 | } 21 | 22 | cleaner::~cleaner() 23 | { 24 | delete dbi; 25 | } 26 | 27 | void cleaner::start() 28 | { 29 | assert(th == nullptr); 30 | 31 | local_stop_flag = false; 32 | 33 | if (check_interval > 0 && purge_interval > 0) 34 | th = new std::thread(std::ref(*this)); 35 | } 36 | 37 | void cleaner::operator()() 38 | { 39 | log(LL_INFO, "Cleaner thread started"); 40 | 41 | set_thread_name("cleaner"); 42 | 43 | for(;!local_stop_flag;) { 44 | log(LL_INFO, "cleaning (check interval: %d, max. file age: %d days)", check_interval, purge_interval); 45 | std::vector files = dbi->purge(purge_interval); 46 | 47 | for(auto file : files) { 48 | log(LL_INFO, "delete file %s", file.c_str()); 49 | 50 | if (unlink(file.c_str()) == -1) 51 | log(LL_ERR, "Cannot delete %s: %s", file.c_str(), strerror(errno)); 52 | } 53 | 54 | mysleep(check_interval * 1000000ll, &local_stop_flag, NULL); 55 | } 56 | 57 | log(LL_INFO, "Cleaner thread terminating"); 58 | } 59 | -------------------------------------------------------------------------------- /src/ws_server.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_WEBSOCKETPP == 1 5 | #include 6 | #include "cfg.h" 7 | 8 | #include 9 | #include 10 | 11 | typedef websocketpp::server server; 12 | 13 | using websocketpp::connection_hdl; 14 | using websocketpp::lib::placeholders::_1; 15 | using websocketpp::lib::placeholders::_2; 16 | using websocketpp::lib::bind; 17 | 18 | class http_server; 19 | class http_cookies; 20 | 21 | class ws_server : public interface 22 | { 23 | private: 24 | server m_server; 25 | 26 | protected: 27 | configuration_t *const cfg; 28 | const listen_adapter_t la; 29 | http_server *const hs; 30 | const bool use_auth; 31 | http_cookies *const c; 32 | 33 | typedef std::set> con_list; 34 | con_list m_connections; 35 | 36 | std::shared_mutex cache_lock; 37 | std::map cache; 38 | 39 | public: 40 | ws_server(configuration_t *const cfg, const std::string & id, const std::string & descr, const listen_adapter_t & la, http_server *const hs, const bool use_auth, http_cookies *c); 41 | virtual ~ws_server(); 42 | 43 | int get_port() const { return la.port; } 44 | 45 | void on_open(connection_hdl hdl); 46 | void on_close(connection_hdl hdl); 47 | void on_message(connection_hdl hdl, server::message_ptr msg); 48 | void on_fail(websocketpp::connection_hdl hdl); 49 | virtual bool on_validate(connection_hdl hdl); 50 | 51 | virtual std::string address_from_hdl(connection_hdl hdl); 52 | 53 | virtual void push(const std::string & msg, const std::string & cache_under); 54 | 55 | virtual void ws_stop(); 56 | 57 | virtual void operator()() override; 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /src/filter_grayscale.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | 6 | #include "gen.h" 7 | #include "filter_grayscale.h" 8 | 9 | filter_grayscale::filter_grayscale(const to_grayscale_t mode) : mode(mode) 10 | { 11 | } 12 | 13 | filter_grayscale::~filter_grayscale() 14 | { 15 | } 16 | 17 | void filter_grayscale::apply_io(instance *const inst, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *in, uint8_t *out) 18 | { 19 | const int n_pixels = w * h; 20 | 21 | if (mode == G_FAST) { 22 | for(int i=0; i 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct 10 | { 11 | const char *prefix; 12 | } 13 | my_struct_t; 14 | 15 | void *init_plugin(const char *const argument) 16 | { 17 | my_struct_t *a = (my_struct_t *)malloc(sizeof(my_struct_t)); 18 | a -> prefix = NULL; 19 | 20 | return a; 21 | } 22 | 23 | void open_file(void *arg, const char *const fname_prefix, const double fps, const int quality) 24 | { 25 | my_struct_t *a = (my_struct_t *)arg; 26 | 27 | a -> prefix = strdup(fname_prefix); 28 | } 29 | 30 | void write_frame(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame) 31 | { 32 | my_struct_t *a = (my_struct_t *)arg; 33 | 34 | char *fname = NULL; 35 | asprintf(&fname, "%s%lu.pgm", a -> prefix, ts); 36 | 37 | FILE *fh = fopen(fname, "w"); 38 | if (fh) { 39 | fprintf(fh, "P2\n%d %d\n255\n", w, h); 40 | 41 | int c = 0; 42 | for(int y=0; y= 70) { 45 | fprintf(fh, "\n"); 46 | c = 0; 47 | } 48 | 49 | int o = y * w * 3 + x * 3; 50 | int g = (current_frame[o + 0] + current_frame[o + 1] + current_frame[o + 2]) / 3; 51 | 52 | c += fprintf(fh, "%d ", g); 53 | } 54 | } 55 | 56 | fclose(fh); 57 | } 58 | else { 59 | fprintf(stderr, "Failed creating %s: %s\n", fname, strerror(errno)); 60 | } 61 | 62 | free(fname); 63 | } 64 | 65 | void close_file(void *arg) 66 | { 67 | // not applicable for this PGM plugin 68 | } 69 | 70 | void uninit_plugin(void *arg) 71 | { 72 | my_struct_t *a = (my_struct_t *)arg; 73 | 74 | free((void *)a -> prefix); 75 | free(a); 76 | } 77 | -------------------------------------------------------------------------------- /examples/timelapse.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "debug"; 3 | 4 | resize-type = "regular"; 5 | 6 | instances = ({ 7 | instance-name = "video input"; 8 | 9 | source = { 10 | id = "1-1"; 11 | descr = "video source"; 12 | type = "v4l"; 13 | device = "/dev/video0"; 14 | width = 640; 15 | height = 480; 16 | } 17 | 18 | # timelapse 19 | targets = ({ 20 | id = "1-4"; 21 | descr = "timelapse"; 22 | # store in current path 23 | path = "./timelapse"; 24 | prefix = "tl-"; 25 | quality = 100; 26 | restart-interval = 86400; 27 | interval = 86400.0; 28 | override-fps = -1.0; 29 | format = "jpeg"; 30 | stream-writer-plugin-file = ""; 31 | stream-writer-plugin-parameter = ""; 32 | exec-start = ""; 33 | exec-cycle = ""; 34 | exec-end = ""; 35 | filters = ({ 36 | type="text"; 37 | text="%c"; 38 | position="lower-right"; 39 | }) 40 | }) 41 | 42 | http-server = ({ 43 | id = "2-1"; 44 | descr = "web server"; 45 | listen-adapter = "0.0.0.0"; 46 | listen-port = 8070; 47 | snapshot-dir = "./timelapse"; 48 | fps = 15.0; 49 | quality = 75; 50 | time-limit = -1; 51 | resize-width = -1; 52 | resize-height = -1; 53 | motion-compatible = false; 54 | allow-admin = false; 55 | archive-access = true; 56 | is-rest = false; 57 | }) 58 | }) 59 | 60 | -------------------------------------------------------------------------------- /src/filter_overlay.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "error.h" 9 | #include "filter_overlay.h" 10 | #include "picio.h" 11 | 12 | filter_overlay::filter_overlay(const std::string & file, const pos_t & pos) : pos(pos) 13 | { 14 | FILE *fh = fopen(file.c_str(), "rb"); 15 | if (!fh) 16 | error_exit(true, "%s failed to read", file.c_str()); 17 | 18 | read_PNG_file_rgba(true, fh, &w, &h, &pixels); 19 | 20 | fclose(fh); 21 | } 22 | 23 | filter_overlay::~filter_overlay() 24 | { 25 | free(pixels); 26 | } 27 | 28 | void filter_overlay::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 29 | { 30 | auto p = pos_to_xy(pos, this->w, this->h, w, h); 31 | int work_x = std::get<0>(p); 32 | int work_y = std::get<1>(p); 33 | 34 | int cw = std::min(this->w, w); 35 | int ch = std::min(this->h, h); 36 | 37 | if (cw <= 0 || ch <= 0) 38 | return; 39 | 40 | int ex = std::min(w - work_x, cw); 41 | int ey = std::min(h - work_y, ch); 42 | 43 | for(int y=0; yw * 4 + x * 4; 51 | 52 | uint8_t alpha = pixels[pic_offset + 3], ialpha = 255 - alpha; 53 | in_out[out_offset + 0] = (int(pixels[pic_offset + 0]) * alpha + (in_out[out_offset + 0] * ialpha)) / 256; 54 | in_out[out_offset + 1] = (int(pixels[pic_offset + 1]) * alpha + (in_out[out_offset + 1] * ialpha)) / 256; 55 | in_out[out_offset + 2] = (int(pixels[pic_offset + 2]) * alpha + (in_out[out_offset + 2] * ialpha)) / 256; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/motiontrigger-plugins/hue-only.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2019 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | 6 | extern "C" { 7 | 8 | void * init_motion_trigger(const char *const parameter) 9 | { 10 | return nullptr; 11 | } 12 | 13 | // https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both 14 | void rgb_to_hsv(const uint8_t r, const uint8_t g, const uint8_t b, uint8_t *const h, uint8_t *const s, uint8_t *const v) 15 | { 16 | uint8_t rgb_min, rgb_max; 17 | 18 | rgb_min = r < g ? (r < b ? r : b) : (g < b ? g : b); 19 | rgb_max = r > g ? (r > b ? r : b) : (g > b ? g : b); 20 | uint8_t diff = rgb_max - rgb_min; 21 | 22 | *v =rgb_max; 23 | if (*v == 0) 24 | { 25 | *h = 0; 26 | *s = 0; 27 | return; 28 | } 29 | 30 | *s = 255 * long(diff) / *v; 31 | if (*s == 0) 32 | { 33 | *h = 0; 34 | return; 35 | } 36 | 37 | if (rgb_max == r) 38 | *h = 0 + 43 * (g - b) / diff; 39 | else if (rgb_max == g) 40 | *h = 85 + 43 * (b - r) / diff; 41 | else 42 | *h = 171 + 43 * (r - g) / diff; 43 | } 44 | 45 | bool detect_motion(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const pf, uint8_t *const cf, const uint8_t *const pixel_selection_bitmap, char **const meta) 46 | { 47 | int count = 0, idx = 0; 48 | 49 | for(int offset=0; offset 16; 60 | } 61 | 62 | return count > w * h * 0.01; 63 | } 64 | 65 | void uninit_motion_trigger(void *arg) 66 | { 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/selection_mask.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | 6 | #include "selection_mask.h" 7 | #include "error.h" 8 | #include "picio.h" 9 | #include "utils.h" 10 | #include "resize.h" 11 | 12 | selection_mask::selection_mask(resize *const r, const std::string & selection_bitmap) : r(r) 13 | { 14 | cache = pixels = NULL; 15 | cw = ch = w = h = -1; 16 | 17 | #if HAVE_NETPBM == 1 18 | std::string ext = "pbm"; 19 | #else 20 | std::string ext = "png"; 21 | #endif 22 | if (selection_bitmap.size() >= 3) 23 | ext = selection_bitmap.substr(selection_bitmap.length() - 3); 24 | 25 | FILE *fh = fopen(selection_bitmap.c_str(), "rb"); 26 | if (!fh) 27 | error_exit(true, "Cannot open file \"%s\"", selection_bitmap.c_str()); 28 | 29 | #if HAVE_NETPBM == 1 30 | if (ext == "pbm") 31 | load_PBM_file(fh, &w, &h, &pixels); 32 | else 33 | #endif 34 | if (ext == "png") { 35 | uint8_t *temp = NULL; 36 | read_PNG_file_rgba(true, fh, &w, &h, &temp); 37 | 38 | size_t n = IMS(w, h, 1); 39 | pixels = (uint8_t *)malloc(n); 40 | 41 | for(size_t i=0; i= 128; 45 | } 46 | 47 | free(temp); 48 | } 49 | else { 50 | error_exit(false, "File type \"%s\" not understood for the selection mask/bitmap", ext.c_str()); 51 | } 52 | 53 | fclose(fh); 54 | } 55 | 56 | selection_mask::~selection_mask() 57 | { 58 | free(cache); 59 | free(pixels); 60 | } 61 | 62 | uint8_t *selection_mask::get_mask(const int rw, const int rh) 63 | { 64 | if (rw == w && rh == h) 65 | return pixels; 66 | 67 | if (rw == cw && rh == ch) 68 | return cache; 69 | 70 | free(cache); 71 | 72 | r -> do_resize(w, h, pixels, rw, rh, &cache); 73 | 74 | cw = rw; 75 | ch = rh; 76 | 77 | return cache; 78 | } 79 | -------------------------------------------------------------------------------- /src/source-plugins/demo.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../source.h" 9 | #include "../log.h" 10 | 11 | typedef struct 12 | { 13 | source *s; 14 | int w, h; 15 | std::atomic_bool stop_flag; 16 | pthread_t th; 17 | } my_data_t; 18 | 19 | void * thread(void *arg) 20 | { 21 | log(LL_INFO, "source plugin thread started"); 22 | 23 | my_data_t *md = (my_data_t *)arg; 24 | 25 | size_t bytes = md -> w * md -> h * 3; 26 | uint8_t *pic = (uint8_t *)malloc(bytes); 27 | memset(pic, 0x00, bytes); 28 | 29 | int x = md -> w / 2, y = md -> h / 2; 30 | 31 | while(!md -> stop_flag) 32 | { 33 | int o = y * md -> w * 3 + x * 3; 34 | pic[o + 0] ^= 255; 35 | pic[o + 1] ^= 255; 36 | pic[o + 2] ^= 255; 37 | 38 | x += (rand() % 3) - 1; 39 | y += (rand() % 3) - 1; 40 | 41 | if (x < 0) 42 | x = md -> w - 1; 43 | else if (x >= md -> w) 44 | x = 0; 45 | 46 | if (y < 0) 47 | y = md -> h - 1; 48 | else if (y >= md -> h) 49 | y = 0; 50 | 51 | // send RGB frame to constatus 52 | md -> s -> set_frame(E_RGB, pic, bytes); 53 | 54 | usleep(10000); 55 | } 56 | 57 | free(pic); 58 | 59 | log(LL_INFO, "source plugin thread ending"); 60 | 61 | return NULL; 62 | } 63 | 64 | extern "C" void *init_plugin(source *const s, const char *const argument) 65 | { 66 | my_data_t *md = new my_data_t; 67 | md -> s = s; 68 | md -> w = 352; 69 | md -> h = 288; 70 | md -> stop_flag = false; 71 | 72 | s -> set_size(md -> w, md -> h); 73 | 74 | pthread_create(&md -> th, NULL, thread, md); 75 | 76 | return md; 77 | } 78 | 79 | extern "C" void uninit_plugin(void *arg) 80 | { 81 | my_data_t *md = (my_data_t *)arg; 82 | 83 | md -> stop_flag = true; 84 | 85 | pthread_join(md -> th, NULL); 86 | 87 | delete md; 88 | } 89 | -------------------------------------------------------------------------------- /src/filter-plugins/demoocv.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | extern "C" { 11 | 12 | void * init_filter(const char *const parameter) 13 | { 14 | // you can use the parameter for anything you want 15 | // e.g. the filename of a configuration file or 16 | // maybe a variable or whatever 17 | 18 | printf("OpenCV build info: %s, number of threads: %u, using optimized code: %d\n", cv::getBuildInformation().c_str(), cv::getNumThreads(), cv::useOptimized()); 19 | 20 | return NULL; 21 | } 22 | 23 | cv::RNG rng(12345); 24 | 25 | void apply_filter(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, uint8_t *const result) 26 | { 27 | cv::Mat imageWithData = cv::Mat(w * h, 1, CV_8UC3, (void *)current_frame); 28 | cv::Mat reshapedImage = imageWithData.reshape(0, h); 29 | 30 | cv::Mat imageGray; 31 | cv::cvtColor(reshapedImage, imageGray, CV_BGR2GRAY); 32 | 33 | //cv::threshold(imageGray, imageGray, 128, 255, CV_THRESH_BINARY); 34 | cv::Canny(imageGray, imageGray, 100, 100*2, 3); 35 | 36 | std::vector > contours; 37 | std::vector hierarchy; 38 | 39 | cv::findContours(imageGray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0)); 40 | 41 | for(size_t i = 0; i< contours.size(); i++) { 42 | cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255)); 43 | 44 | drawContours(reshapedImage, contours, i, color, 2, 8, hierarchy, 0, cv::Point()); 45 | } 46 | 47 | memcpy(result, reshapedImage.data, w * h * 3); 48 | } 49 | 50 | void uninit_filter(void *arg) 51 | { 52 | // free memory etc 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/motiontrigger-plugins/demoocv2.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017 by folkert van heusden, this file is released in the public domain 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | // #include 9 | 10 | extern "C" { 11 | 12 | void * init_motion_trigger(const char *const parameter) 13 | { 14 | // you can use the parameter for anything you want 15 | // e.g. the filename of a configuration file or 16 | // maybe a variable or whatever 17 | 18 | // what you return here, will be given as a parameter 19 | // to detect_motion 20 | 21 | cv::CascadeClassifier *face_cascade = new cv::CascadeClassifier(); 22 | if (!face_cascade -> load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml")) 23 | printf("load failed\n"); 24 | 25 | return face_cascade; 26 | } 27 | 28 | bool detect_motion(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, uint8_t *const current_frame, const uint8_t *const pixel_selection_bitmap, char **const meta) 29 | { 30 | cv::CascadeClassifier *face_cascade = (cv::CascadeClassifier *)arg; 31 | 32 | cv::Mat frame = cv::Mat(h, w, CV_8UC3, (void *)current_frame); 33 | 34 | cv::Mat frame_gray; 35 | cv::cvtColor(frame, frame_gray, cv::COLOR_BGR2GRAY); 36 | cv::equalizeHist(frame_gray, frame_gray); 37 | 38 | // cv::imwrite("gray.png", frame_gray); 39 | // cv::imwrite("rgb.png", frame); 40 | // exit(0); 41 | 42 | std::vector faces; 43 | face_cascade -> detectMultiScale(frame_gray, faces, 1.1, 2, 0 | cv::CASCADE_SCALE_IMAGE, cv::Size(30, 30)); 44 | 45 | frame_gray.release(); 46 | frame.release(); 47 | 48 | return !faces.empty(); 49 | } 50 | 51 | void uninit_motion_trigger(void *arg) 52 | { 53 | // free memory etc 54 | delete (cv::CascadeClassifier *)arg; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/filter_overlay_on_motion.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "exec.h" 8 | #include "error.h" 9 | #include "gen.h" 10 | #include "filter_overlay_on_motion.h" 11 | #include "instance.h" 12 | #include "motion_trigger.h" 13 | #include "resize.h" 14 | #include "utils.h" 15 | #include "view.h" 16 | 17 | 18 | filter_overlay_on_motion::filter_overlay_on_motion(instance *const i, source *const cks, resize *const r, const int display_time_ms) : 19 | i(i), 20 | cks(cks), 21 | r(r), 22 | display_time_ms(display_time_ms) 23 | { 24 | cks->start(); 25 | 26 | for(auto mi : find_motion_triggers(i)) 27 | static_cast(mi)->register_notifier(this); 28 | } 29 | 30 | filter_overlay_on_motion::~filter_overlay_on_motion() 31 | { 32 | for(auto mi : find_motion_triggers(i)) 33 | static_cast(mi)->unregister_notifier(this); 34 | } 35 | 36 | void filter_overlay_on_motion::notify_thread_of_event(const std::string & subject) 37 | { 38 | changed = true; 39 | 40 | // TODO locking 41 | since = get_us() / 1000; 42 | } 43 | 44 | void filter_overlay_on_motion::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 45 | { 46 | if (!changed) 47 | return; 48 | 49 | if (get_us() / 1000 - since >= display_time_ms) { 50 | changed = false; 51 | return; 52 | } 53 | 54 | // OVERLAY 55 | video_frame *vf = cks->get_frame(true, ts); 56 | 57 | if (vf) { 58 | const int in_w = vf->get_w(); 59 | const int in_h = vf->get_h(); 60 | 61 | int perc = std::max(1, std::min(w * 100 / in_w, h * 100 / in_h)); 62 | 63 | pos_t p { center_center, 0, 0 }; 64 | 65 | picture_in_picture(r, in_out, w, h, vf->get_data(E_RGB), in_w, in_h, perc, p); 66 | 67 | delete vf; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/target.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "interface.h" 9 | #include "cfg.h" 10 | 11 | class filter; 12 | class schedule; 13 | class source; 14 | class target; 15 | 16 | extern std::string default_fmt; 17 | 18 | std::string gen_filename(source *const s, const std::string & fmt, const std::string & store_path, const std::string & prefix, const std::string & ext, const uint64_t ts, const unsigned f_nr); 19 | 20 | class target : public interface 21 | { 22 | protected: 23 | source *const s; 24 | const std::string store_path, prefix, fmt; 25 | const int max_time; 26 | const double interval; 27 | const std::vector *const filters; 28 | const std::string exec_start, exec_cycle, exec_end; 29 | const double override_fps; 30 | configuration_t *const cfg; 31 | const bool is_view_proxy, handle_failure; 32 | schedule *const sched; 33 | 34 | std::vector pre_record; 35 | 36 | unsigned long current_event_nr; 37 | 38 | std::thread *exec_start_th { nullptr }; 39 | std::thread *exec_end_th { nullptr }; 40 | 41 | void register_file(const std::string & filename); 42 | 43 | public: 44 | target(const std::string & id, const std::string & descr, source *const s, const std::string & store_path, const std::string & prefix, const std::string & fmt, const int max_time, const double interval, const std::vector *const filters, const std::string & exec_start, const std::string & exec_cycle, const std::string & exec_end, const double override_fps, configuration_t *const cfg, const bool is_view_proxy, const bool handle_failure, schedule *const sched); 45 | virtual ~target(); 46 | 47 | void start(std::vector & pre_record, const unsigned long event_nr); 48 | 49 | std::string get_target_dir() const { return store_path; } 50 | 51 | virtual void operator()() = 0; 52 | }; 53 | -------------------------------------------------------------------------------- /src/motion_trigger_generic.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "motion_trigger.h" 8 | 9 | class filter; 10 | class parameter; 11 | class selection_mask; 12 | class source; 13 | class target; 14 | 15 | typedef void * (*init_motion_trigger_t)(const char *const par); 16 | typedef bool (*detect_motion_t)(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, const uint8_t *const current_frame, const uint8_t *const pixel_selection_bitmap, char **const meta); 17 | typedef void (*uninit_motion_trigger_t)(void *arg); 18 | 19 | typedef struct 20 | { 21 | void *library; 22 | 23 | init_motion_trigger_t init_motion_trigger; 24 | detect_motion_t detect_motion; 25 | uninit_motion_trigger_t uninit_motion_trigger; 26 | 27 | std::string par; 28 | 29 | void *arg; 30 | } ext_trigger_t; 31 | 32 | class motion_trigger_generic : public motion_trigger 33 | { 34 | private: 35 | source *const s; 36 | 37 | std::atomic_bool motion_triggered; 38 | 39 | const int camera_warm_up; 40 | 41 | const std::vector *const filters; 42 | 43 | ext_trigger_t *const et; 44 | selection_mask *const pixel_select_bitmap; 45 | std::string exec_start, exec_end; 46 | 47 | instance *const inst; 48 | 49 | public: 50 | motion_trigger_generic(const std::string & id, const std::string & descr, source *const s, const int camera_warm_up, const std::vector *const filters, std::vector *const targets, selection_mask *const pixel_select_bitmap, ext_trigger_t *const et, const std::string & e_start, const std::string & e_end, instance *const inst, const std::map & detection_parameters, schedule *const sched); 51 | virtual ~motion_trigger_generic(); 52 | 53 | bool check_motion() override { return motion_triggered; } 54 | 55 | void operator()() override; 56 | }; 57 | -------------------------------------------------------------------------------- /src/source_libcamera.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | #include "config.h" 4 | #if HAVE_LIBCAMERA == 1 || HAVE_LIBCAMERA2 == 1 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "source.h" 12 | 13 | class controls; 14 | class parameter; 15 | 16 | class source_libcamera : public source 17 | { 18 | protected: 19 | const std::string dev; 20 | const int w_requested, h_requested; 21 | const bool prefer_jpeg; 22 | const std::map ctrls; 23 | const int rotate_angle; 24 | 25 | libcamera::CameraManager *cm{ nullptr }; 26 | std::shared_ptr camera; 27 | libcamera::FrameBufferAllocator *allocator{ nullptr }; 28 | libcamera::Stream *stream{ nullptr }; 29 | std::vector > requests; 30 | std::map> mappedBuffers; 31 | 32 | uint32_t pixelformat{ 0 }; 33 | 34 | void request_completed(libcamera::Request *request); 35 | 36 | public: 37 | source_libcamera(const std::string & id, const std::string & descr, const std::string & exec_failure, const std::string & dev, const int jpeg_quality, const double max_fps, const int w_requested, const int h_requested, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, const bool prefer_jpeg, const std::map & ctrls, controls *const c, const int rotate_angle, const std::map & text_feeds, const bool keep_aspectratio); 38 | virtual ~source_libcamera(); 39 | 40 | static void list_devices(); 41 | 42 | virtual void pan_tilt(const double abs_pan, const double abs_tilt) override; 43 | virtual void get_pan_tilt(double *const pan, double *const tilt) const override; 44 | 45 | virtual void operator()() override; 46 | }; 47 | #endif 48 | -------------------------------------------------------------------------------- /src/motiontrigger-plugins/Makefile: -------------------------------------------------------------------------------- 1 | # (C) 2017-2020 by folkert van heusden, this file is released in the public domain 2 | INSTALL_PREFIX=/usr/local 3 | 4 | CXXFLAGS=-fPIC -Wall -ggdb3 `pkg-config --cflags opencv4` -std=c++17 -I../build 5 | VERSION=0.1 6 | 7 | OBJS1=demo.o 8 | OBJS2=demoocv.o 9 | OBJS3=demoocv2.o 10 | OBJS4=hue-only.o 11 | OBJS5=gpio.o 12 | OBJS6=network.o 13 | OBJS7=objects-test.o 14 | 15 | all: lib1 lib2 lib3 lib4 lib5 lib6 lib7 16 | 17 | lib1: $(OBJS1) 18 | ar -r demo.a $(OBJS1) 19 | ld -g -x -lm -shared -soname demo.so.2 -o demo.so.$(VERSION) --whole-archive demo.a 20 | 21 | lib2: $(OBJS2) 22 | ar -r demoocv.a $(OBJS2) 23 | ld -g -x -lm `pkg-config --libs opencv4` -shared -soname demoocv.so.2 -o demoocv.so.$(VERSION) --whole-archive demoocv.a 24 | 25 | lib3: $(OBJS3) 26 | ar -r demoocv2.a $(OBJS3) 27 | ld -g -x -lm `pkg-config --libs opencv4` -shared -soname demoocv2.so.2 -o demoocv2.so.$(VERSION) --whole-archive demoocv2.a 28 | 29 | lib4: $(OBJS4) 30 | ar -r hue-only.a $(OBJS4) 31 | ld -g -x -lm -shared -soname hue-only.so.2 -o hue-only.so.$(VERSION) --whole-archive hue-only.a 32 | 33 | lib5: $(OBJS5) 34 | ar -r gpio.a $(OBJS5) 35 | ld -g -x -lm -shared -soname gpio.so.2 -o gpio.so.$(VERSION) --whole-archive gpio.a 36 | 37 | lib6: $(OBJS6) 38 | ar -r network.a $(OBJS6) 39 | ld -g -x -lm -shared -soname network.so.2 -o network.so.$(VERSION) --whole-archive network.a 40 | 41 | lib7: $(OBJS7) 42 | ar -r objects-test.a $(OBJS7) 43 | ld -g -x -lm -shared -soname objects-test.so.2 -o objects-test.so.$(VERSION) --whole-archive objects-test.a 44 | 45 | install: all 46 | cp demo*.so.* network*.so.* gpio*.so.* objects-test*.so.* $(INSTALL_PREFIX)/lib 47 | /sbin/ldconfig 48 | 49 | uninstall: clean 50 | rm -f $(INSTALL_PREFIX)/lib/demo*.so.* $(INSTALL_PREFIX)/lib/gpio*.so.* $(INSTALL_PREFIX)/lib/network*.so.* $(INSTALL_PREFIX)/lib/objects-test*.so.* 51 | 52 | clean: 53 | rm -f $(OBJS1) core $(OBJS2) $(OBJS3) *.a *.so.* $(OBJS5) $(OBJS6) $(OBJS7) 54 | -------------------------------------------------------------------------------- /src/video_frame.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "encoding.h" 10 | 11 | class controls; 12 | class filter; 13 | class instance; 14 | class meta; 15 | class resize; 16 | class source; 17 | 18 | class video_frame 19 | { 20 | private: 21 | mutable std::mutex m; 22 | 23 | const meta *const m_; 24 | const int jpeg_quality; 25 | 26 | uint64_t ts { 0 }; 27 | int w { -1 }, h { -1 }; 28 | 29 | std::map > data; 30 | 31 | std::map >::iterator gen_encoding(const encoding_t new_e); 32 | std::tuple get_data_and_len_internal(const encoding_t e); 33 | 34 | video_frame(const meta *const m, const int jpeg_quality); 35 | 36 | public: 37 | video_frame(const meta *const m, const int jpeg_quality, const uint64_t ts, const int w, const int h, uint8_t *const data, const size_t len, const encoding_t e); 38 | virtual ~video_frame(); 39 | 40 | void set_ts(const uint64_t ts); 41 | void set_wh(const int w, const int h); 42 | void put_data(const uint8_t *const data, const size_t len, const encoding_t e); // makes a copy 43 | void set_encoding(const encoding_t e); 44 | 45 | int get_w() const; 46 | int get_h() const; 47 | uint8_t *get_data(const encoding_t e); 48 | std::tuple get_data_and_len(const encoding_t e); 49 | std::tuple get_wh() const; 50 | uint64_t get_ts() const; 51 | void keep_only_format(const encoding_t e); 52 | 53 | video_frame *duplicate(const std::optional e); 54 | video_frame *do_resize(resize *const r, const int new_w, const int new_h); 55 | video_frame *apply_filtering(instance *const inst, source *const s, video_frame *const prev, const std::vector *const filters, controls *const c); 56 | video_frame *do_rotate(const int angle); 57 | }; 58 | -------------------------------------------------------------------------------- /src/meta.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "gen.h" 10 | 11 | class meta; 12 | typedef void *(* init_plugin_t)(meta *const m, const char *const argument); 13 | typedef void (* uninit_plugin_t)(void *arg); 14 | 15 | typedef struct 16 | { 17 | init_plugin_t init_plugin; 18 | uninit_plugin_t uninit_plugin; 19 | void *handle, *arg; 20 | } meta_plugin_t; 21 | 22 | class meta 23 | { 24 | private: 25 | mutable std::shared_mutex m_int_lock; 26 | std::map > m_int; 27 | mutable std::shared_mutex m_double_lock; 28 | std::map > m_double; 29 | mutable std::shared_mutex m_string_lock; 30 | std::map > m_string; 31 | mutable std::shared_mutex m_bitmap_lock; 32 | std::map > m_bitmap; 33 | 34 | std::vector plugins; 35 | 36 | public: 37 | meta(); 38 | ~meta(); 39 | 40 | void add_plugin(const std::string & filename, const std::string & parameter); 41 | 42 | bool get_int(const std::string & key, std::pair *const val) const; 43 | void set_int(const std::string & key, const std::pair & v); 44 | 45 | bool get_double(const std::string & key, std::pair *const val) const; 46 | void set_double(const std::string & key, const std::pair & v); 47 | 48 | bool get_string(const std::string & key, std::pair *const val) const; 49 | void set_string(const std::string & key, const std::pair & v); 50 | 51 | bool get_bitmap(const std::string & key, std::pair *const val) const; 52 | void set_bitmap(const std::string & key, const std::pair & v); 53 | std::vector get_bitmap_keys() const; 54 | }; 55 | -------------------------------------------------------------------------------- /src/source_plugin.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "error.h" 8 | #include "http_client.h" 9 | #include "source.h" 10 | #include "source_plugin.h" 11 | #include "picio.h" 12 | #include "filter.h" 13 | #include "log.h" 14 | #include "utils.h" 15 | #include "controls.h" 16 | 17 | source_plugin::source_plugin(const std::string & id, const std::string & descr, const int w, const int h, const std::string & exec_failure, const std::string & plugin_filename, const std::string & plugin_arg, const double max_fps, resize *const r, const int resize_w, const int resize_h, const int loglevel, const double timeout, std::vector *const filters, const failure_t & failure, controls *const c, const int jpeg_quality, const std::map & text_feeds, const bool keep_aspectratio) : 18 | source(id, descr, exec_failure, max_fps, w, h, loglevel, filters, failure, c, jpeg_quality, text_feeds, keep_aspectratio) 19 | { 20 | library = dlopen(plugin_filename.c_str(), RTLD_NOW); 21 | if (!library) 22 | error_exit(true, "Failed opening source plugin library %s: %s", plugin_filename.c_str(), dlerror()); 23 | 24 | init_plugin = (sp_init_plugin_t)find_symbol(library, "init_plugin", "video source plugin", plugin_filename.c_str()); 25 | uninit_plugin = (sp_uninit_plugin_t)find_symbol(library, "uninit_plugin", "video source plugin", plugin_filename.c_str()); 26 | 27 | arg = init_plugin(this, plugin_arg.c_str()); 28 | } 29 | 30 | source_plugin::~source_plugin() 31 | { 32 | stop(); 33 | 34 | uninit_plugin(arg); 35 | 36 | dlclose(library); 37 | 38 | delete c; 39 | } 40 | 41 | void source_plugin::operator()() 42 | { 43 | log(id, LL_INFO, "source plugins thread started"); 44 | 45 | set_thread_name("src_plugins"); 46 | 47 | // all work is performed in the plugin itself 48 | for(;!local_stop_flag;) 49 | myusleep(101000); 50 | 51 | register_thread_end("source plugin"); 52 | } 53 | -------------------------------------------------------------------------------- /src/motiontrigger-plugins/network.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2021-2023 by folkert van heusden, this file is released under the MIT license 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../error.h" 13 | #include "../utils.h" 14 | 15 | extern "C" { 16 | 17 | typedef struct { 18 | std::atomic_uint64_t triggered; 19 | int fd, port; 20 | pthread_t th; 21 | } arg_t; 22 | 23 | void * listen_thread(void *arg) 24 | { 25 | arg_t *a = (arg_t *)arg; 26 | 27 | char buffer[8]; 28 | for(;;) { 29 | int rc = recv(a->fd, buffer, sizeof buffer, 0); 30 | 31 | if (rc >= 0) 32 | a->triggered = get_us(); 33 | else 34 | break; 35 | } 36 | 37 | return nullptr; 38 | } 39 | 40 | void * init_motion_trigger(const char *const parameter) 41 | { 42 | arg_t *a = new arg_t; 43 | 44 | a->port = atoi(parameter); 45 | 46 | a->fd = socket(AF_INET, SOCK_DGRAM, 0); 47 | if (a->fd == -1) 48 | error_exit(true, "Failed to create datagram socket"); 49 | 50 | struct sockaddr_in address{ 0 }; 51 | address.sin_family = AF_INET; 52 | address.sin_addr.s_addr = INADDR_ANY; 53 | address.sin_port = htons(a->port); 54 | if (bind(a->fd, (struct sockaddr *)&address, sizeof(address)) == -1) 55 | error_exit(true, "Failed to bind socket to port %d", a->port); 56 | 57 | pthread_create(&a->th, nullptr, listen_thread, a); 58 | 59 | return a; 60 | } 61 | 62 | bool detect_motion(void *arg, const uint64_t ts, const int w, const int h, const uint8_t *const prev_frame, uint8_t *const current_frame, const uint8_t *const pixel_selection_bitmap, char **const meta) 63 | { 64 | arg_t *a = (arg_t *)arg; 65 | 66 | bool rc = a -> triggered.exchange(0) != 0; 67 | 68 | return rc; 69 | } 70 | 71 | void uninit_motion_trigger(void *arg) 72 | { 73 | arg_t *a = (arg_t *)arg; 74 | 75 | close(a->fd); 76 | 77 | pthread_join(a->th, nullptr); 78 | 79 | delete a; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /examples/overlay-on-motion.cfg: -------------------------------------------------------------------------------- 1 | logfile = "test.log"; 2 | log-level = "info"; 3 | 4 | resize-type = "regular"; 5 | resize-crop-center = true; 6 | 7 | instances = ( 8 | { 9 | instance-name = "jpegs-via-mqtt"; 10 | 11 | source = { 12 | id = "1-1"; 13 | type = "v4l"; 14 | device = "/dev/video0"; 15 | width = 640; 16 | height = 480; 17 | pixel-format = "RGB3"; 18 | } 19 | 20 | motion-trigger = ( 21 | # here we wait for motion in the video stream 22 | { 23 | id = "1-2"; 24 | descr = "motion trigger(s)"; 25 | 26 | noise-factor = 32; 27 | min-pixels-changed-percentage = 0.02; 28 | max-pixels-changed-percentage = 99.0; 29 | min-duration = 1; 30 | mute-duration = 1; 31 | pre-motion-record-duration = 0; 32 | 33 | warmup-duration = 0; 34 | max-fps = -1.0; 35 | 36 | trigger-plugin-file = ""; 37 | trigger-plugin-parameter = ""; 38 | 39 | selection-bitmap = ""; 40 | 41 | filters-detection = [ ]; 42 | exec-start = ""; 43 | exec-end = ""; 44 | 45 | targets = ( 46 | ) 47 | } 48 | ) 49 | }, 50 | { 51 | instance-name = "irssi-stream"; 52 | 53 | source = { 54 | id = "2-1"; 55 | descr = "irssi as a png streawm"; 56 | type = "mpng"; 57 | fps = 3.0; 58 | resize-width = 1280; 59 | resize-height = 800; 60 | max-fps = -1.0; 61 | url = "http://vps001.vanheusden.com:8888"; 62 | timeout = 10.0; 63 | 64 | filters = ( 65 | { 66 | type = "overlay-on-motion"; 67 | motion-source = "jpegs-via-mqtt"; 68 | other-id = "1-1"; 69 | display-time = 5000; 70 | } 71 | ); 72 | } 73 | } 74 | ) 75 | 76 | global-http-server = ( 77 | { 78 | id = "2-1"; 79 | descr = "mjpeg out"; 80 | listen-adapter = "0.0.0.0"; 81 | listen-port = 8070; 82 | fps = 15.0; 83 | quality = 50; 84 | stylesheet = "stylesheet.css"; 85 | time-limit = -1; 86 | resize-width = -1; 87 | resize-height = -1; 88 | motion-compatible = false; 89 | allow-admin = false; 90 | archive-access = false; 91 | is-rest = false; 92 | } 93 | ) 94 | -------------------------------------------------------------------------------- /src/filter.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #include "gen.h" 8 | #include "filter.h" 9 | #include "log.h" 10 | #include "utils.h" 11 | 12 | void apply_filters(instance *const i, interface *const specific_int, const std::vector *const filters, const uint8_t *const prev, uint8_t *const work, const uint64_t ts, const int w, const int h) 13 | { 14 | if (!filters) 15 | return; 16 | 17 | const size_t bytes = IMS(w, h, 3); 18 | uint8_t *temp = nullptr; 19 | 20 | bool flag = false; 21 | for(filter *f : *filters) { 22 | if (f -> uses_in_out()) { 23 | if (!temp) 24 | temp = (uint8_t *)malloc(bytes); 25 | 26 | if (flag == false) 27 | f -> apply_io(i, specific_int, ts, w, h, prev, work, temp); 28 | else 29 | f -> apply_io(i, specific_int, ts, w, h, prev, temp, work); 30 | 31 | flag = !flag; 32 | } 33 | else { 34 | if (flag == false) 35 | f -> apply(i, specific_int, ts, w, h, prev, work); 36 | else 37 | f -> apply(i, specific_int, ts, w, h, prev, temp); 38 | } 39 | } 40 | 41 | if (flag == true) 42 | memcpy(work, temp, bytes); 43 | 44 | free(temp); 45 | } 46 | 47 | void free_filters(const std::vector *filters) 48 | { 49 | if (filters) { 50 | for(filter *f : *filters) 51 | delete f; 52 | 53 | delete filters; 54 | } 55 | } 56 | 57 | filter::filter() : interface("filter", "filter") 58 | { 59 | ct = CT_FILTER; 60 | } 61 | 62 | filter::~filter() 63 | { 64 | } 65 | 66 | void filter::apply_io(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, const uint8_t *const in, uint8_t *const out) 67 | { 68 | log(id, LL_FATAL, "filter::apply_io should not be called"); 69 | } 70 | 71 | void filter::apply(instance *const i, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 72 | { 73 | log(id, LL_FATAL, "filter::apply should not be called"); 74 | } 75 | -------------------------------------------------------------------------------- /src/resize_crop.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "resize_crop.h" 9 | #include "log.h" 10 | #include "utils.h" 11 | 12 | resize_crop::resize_crop(const bool resize_crop_center, const bool fill_max) : resize_crop_center(resize_crop_center), fill_max(fill_max) 13 | { 14 | log(LL_INFO, "Generic resize_crop instantiated"); 15 | } 16 | 17 | resize_crop::~resize_crop() 18 | { 19 | } 20 | 21 | void resize_crop::do_resize(const int win, const int hin, const uint8_t *const in, const int wout, const int hout, uint8_t **out) 22 | { 23 | size_t out_size = IMS(wout, hout, 3); 24 | 25 | *out = (uint8_t *)allocate_0x00(out_size); 26 | 27 | if (fill_max) { 28 | // resize 29 | double scale_w = wout / double(win); 30 | double scale_h = hout / double(hin); 31 | 32 | double diff_w = fabs(1.0 - scale_w); 33 | double diff_h = fabs(1.0 - scale_h); 34 | 35 | int temp_w = 0, temp_h = 0; 36 | 37 | if (diff_w < diff_h) { 38 | temp_w = wout; 39 | temp_h = hout * scale_h; 40 | } 41 | else { 42 | temp_w = wout * scale_w; 43 | temp_h = hout; 44 | } 45 | 46 | uint8_t *temp = nullptr; 47 | resize::do_resize(win, hin, in, temp_w, temp_h, &temp); 48 | 49 | // crop 50 | int xoffset = resize_crop_center && wout > temp_w ? (wout - temp_w) / 2 : 0; 51 | int yoffset = resize_crop_center && hout > temp_h ? (hout - temp_h) / 2 : 0; 52 | 53 | int new_width = std::min(temp_w, wout); 54 | 55 | for(int y=0; y win ? (wout - win) / 2 : 0; 62 | int yoffset = resize_crop_center && hout > hin ? (hout - hin) / 2 : 0; 63 | 64 | int new_width = std::min(win, wout); 65 | 66 | for(int y=0; y 4 | 5 | #include "http_cookies.h" 6 | #include "utils.h" 7 | 8 | http_cookies::http_cookies() 9 | { 10 | } 11 | 12 | http_cookies::~http_cookies() 13 | { 14 | } 15 | 16 | void http_cookies::clean_cookies(const int max_age) 17 | { 18 | const std::lock_guard lck(lock); 19 | 20 | std::vector to_erase; 21 | time_t now = time(nullptr); 22 | 23 | for(auto it : cookies) { 24 | if (it.second.second + max_age < now) 25 | to_erase.push_back(it.first); 26 | } 27 | 28 | for(auto cookie : to_erase) 29 | cookies.erase(cookies.find(cookie)); 30 | } 31 | 32 | std::string http_cookies::get_cookie(const std::string & user) 33 | { 34 | std::string rc; 35 | 36 | const std::lock_guard lck(lock); 37 | 38 | for(auto it : cookies) { 39 | if (it.second.first == user) { 40 | rc = it.first; 41 | break; 42 | } 43 | } 44 | 45 | if (rc.empty()) { 46 | // gen & insert 47 | constexpr int rnd_len = 16; 48 | uint8_t *rnd = gen_random(rnd_len); 49 | std::string rnd_str = bin_to_hex(rnd, rnd_len); 50 | free(rnd); 51 | 52 | cookies.insert({ rnd_str, { user, time(nullptr) } }); 53 | 54 | rc = rnd_str; 55 | } 56 | 57 | return rc; 58 | } 59 | 60 | std::string http_cookies::get_cookie_user(const std::string & cookie_key) 61 | { 62 | std::string rc; 63 | 64 | const std::lock_guard lck(lock); 65 | 66 | auto it = cookies.find(cookie_key); 67 | if (it != cookies.end()) 68 | rc = it->second.first; 69 | 70 | return rc; 71 | } 72 | 73 | void http_cookies::update_cookie(const std::string & user, const std::string & key) 74 | { 75 | const std::lock_guard lck(lock); 76 | 77 | auto it = cookies.find(key); 78 | if (it != cookies.end()) 79 | it->second.second = time(nullptr); 80 | } 81 | 82 | void http_cookies::delete_cookie_for_user(const std::string & user) 83 | { 84 | const std::lock_guard lck(lock); 85 | 86 | std::vector to_erase; 87 | 88 | for(auto it : cookies) { 89 | if (it.first == user) { 90 | cookies.erase(cookies.find(it.first)); 91 | break; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/filter_motion_only.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2023 by folkert van heusden, released under the MIT license 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "gen.h" 9 | #include "filter_motion_only.h" 10 | #include "log.h" 11 | #include "utils.h" 12 | #include "selection_mask.h" 13 | 14 | filter_motion_only::filter_motion_only(selection_mask *const pixel_select_bitmap, const int noise_level, const bool diff_value) : pixel_select_bitmap(pixel_select_bitmap), noise_level(noise_level), diff_value(diff_value) 15 | { 16 | prev1 = prev2 = nullptr; 17 | } 18 | 19 | filter_motion_only::~filter_motion_only() 20 | { 21 | delete pixel_select_bitmap; 22 | 23 | free(prev1); 24 | free(prev2); 25 | } 26 | 27 | void filter_motion_only::apply(instance *const inst, interface *const specific_int, const uint64_t ts, const int w, const int h, const uint8_t *const prev, uint8_t *const in_out) 28 | { 29 | if (!prev) 30 | return; 31 | 32 | size_t n = IMS(w, h, 3); 33 | 34 | if (prev1 == nullptr) { 35 | prev1 = (uint8_t *)malloc(n); 36 | prev2 = (uint8_t *)malloc(n); 37 | } 38 | 39 | memcpy(prev1, in_out, n); 40 | 41 | const int nl3 = noise_level * 3; 42 | 43 | uint8_t *psb = pixel_select_bitmap ? pixel_select_bitmap -> get_mask(w, h) : nullptr; 44 | 45 | if (psb) { 46 | for(int i=0; i