mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-03-17 21:13:42 +00:00
gpio
This commit is contained in:
4
Makefile
4
Makefile
@@ -30,9 +30,9 @@ ifneq ($(call optbool,$(WITH_OMX_ENCODER)),)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
ifneq ($(call optbool,$(WITH_WORKERS_GPIO_DEBUG)),)
|
ifneq ($(call optbool,$(WITH_GPIO)),)
|
||||||
LIBS += -lwiringPi
|
LIBS += -lwiringPi
|
||||||
override CFLAGS += -DWITH_WORKERS_GPIO_DEBUG
|
override CFLAGS += -DWITH_GPIO
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
| Streaming via UNIX domain socket |  Yes |  No |
|
| Streaming via UNIX domain socket |  Yes |  No |
|
||||||
| Debug logs without recompiling,<br>performance statistics log,<br>access to HTTP broadcast parameters |  Yes |  No |
|
| Debug logs without recompiling,<br>performance statistics log,<br>access to HTTP broadcast parameters |  Yes |  No |
|
||||||
| Option to serve files<br>with a built-in HTTP server |  Yes |  Regular files only |
|
| Option to serve files<br>with a built-in HTTP server |  Yes |  Regular files only |
|
||||||
|
| Signaling about the stream state to GPIO<br>on Raspberry Pi using [wiringPi](http://wiringpi.com) |  Yes |  No |
|
||||||
| Access to webcam controls (focus, servos)<br>and settings such as brightness via HTTP |  No |  Yes |
|
| Access to webcam controls (focus, servos)<br>and settings such as brightness via HTTP |  No |  Yes |
|
||||||
|
|
||||||
Footnotes:
|
Footnotes:
|
||||||
@@ -31,7 +32,7 @@ If you're going to live-stream from your backyard webcam and need to control it,
|
|||||||
# Building
|
# Building
|
||||||
You'll need ```make```, ```gcc```, ```libevent``` with ```pthreads``` support, ```libjpeg8```/```libjpeg-turbo``` and ```libuuid```.
|
You'll need ```make```, ```gcc```, ```libevent``` with ```pthreads``` support, ```libjpeg8```/```libjpeg-turbo``` and ```libuuid```.
|
||||||
|
|
||||||
On Raspberry Pi you can build the program with OpenMAX IL. To do this pass option ```WITH_OMX_ENCODER=1``` to ```make```.
|
On Raspberry Pi you can build the program with OpenMAX IL. To do this pass option ```WITH_OMX_ENCODER=1``` to ```make```. To enable GPIO support install [wiringPi](http://wiringpi.com) and pass option ```WITH_GPIO=1```.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git clone --depth=1 https://github.com/pi-kvm/ustreamer
|
$ git clone --depth=1 https://github.com/pi-kvm/ustreamer
|
||||||
@@ -40,7 +41,7 @@ $ make
|
|||||||
$ ./ustreamer --help
|
$ ./ustreamer --help
|
||||||
```
|
```
|
||||||
|
|
||||||
AUR has a package for Arch Linux: https://aur.archlinux.org/packages/ustreamer. It should compile automatically with OpenMAX IL on Raspberry Pi, if the corresponding headers are present in ```/opt/vc/include```.
|
AUR has a package for Arch Linux: https://aur.archlinux.org/packages/ustreamer. It should compile automatically with OpenMAX IL on Raspberry Pi, if the corresponding headers are present in ```/opt/vc/include```. Same with GPIO.
|
||||||
FreeBSD port: https://www.freshports.org/multimedia/ustreamer.
|
FreeBSD port: https://www.freshports.org/multimedia/ustreamer.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
| Стрим через UNIX domain socket |  Есть |  Нет |
|
| Стрим через UNIX domain socket |  Есть |  Нет |
|
||||||
| Дебаг-логи без перекомпиляции,<br>логгирование статистики производительности,<br>возможность получения параметров<br>трансляции по HTTP |  Есть |  Нет |
|
| Дебаг-логи без перекомпиляции,<br>логгирование статистики производительности,<br>возможность получения параметров<br>трансляции по HTTP |  Есть |  Нет |
|
||||||
| Возможность сервить файлы встроенным<br>HTTP-сервером |  Есть |  Нет каталогов |
|
| Возможность сервить файлы встроенным<br>HTTP-сервером |  Есть |  Нет каталогов |
|
||||||
|
| Вывод сигналов о состоянии стрима на GPIO<br>на Raspberry Pi с помощью [wiringPi](http://wiringpi.com) |  Есть |  Нет |
|
||||||
| Поддержка контролов веб-камер (фокус,<br> движение сервами) и всяких настроек,<br> типа яркости, через HTTP |  Нет |  Есть |
|
| Поддержка контролов веб-камер (фокус,<br> движение сервами) и всяких настроек,<br> типа яркости, через HTTP |  Нет |  Есть |
|
||||||
|
|
||||||
Сносочки:
|
Сносочки:
|
||||||
@@ -31,7 +32,7 @@
|
|||||||
# Сборка
|
# Сборка
|
||||||
Для сборки вам понадобятся ```make```, ```gcc```, ```libevent``` с поддержкой ```pthreads```, ```libjpeg8```/```libjpeg-turbo``` и ```libuuid```.
|
Для сборки вам понадобятся ```make```, ```gcc```, ```libevent``` с поддержкой ```pthreads```, ```libjpeg8```/```libjpeg-turbo``` и ```libuuid```.
|
||||||
|
|
||||||
На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX_ENCODER=1```.
|
На Raspberry Pi программу можно собрать с поддержкой OpenMAX IL. Для этого передайте ```make``` параметр ```WITH_OMX_ENCODER=1```. Для включения сборки с поддержкой GPIO установите [wiringPi](http://wiringpi.com) и добавьте параметр ```WITH_GPIO=1```.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ git clone --depth=1 https://github.com/pi-kvm/ustreamer
|
$ git clone --depth=1 https://github.com/pi-kvm/ustreamer
|
||||||
@@ -40,7 +41,7 @@ $ make
|
|||||||
$ ./ustreamer --help
|
$ ./ustreamer --help
|
||||||
```
|
```
|
||||||
|
|
||||||
Для Arch Linux в AUR есть готовый пакет: https://aur.archlinux.org/packages/ustreamer. На Raspberry Pi програма автоматически собирается с поддержкой OpenMAX IL, если обнаружит нужные хедеры в ```/opt/vc/include```.
|
Для Arch Linux в AUR есть готовый пакет: https://aur.archlinux.org/packages/ustreamer. На Raspberry Pi програма автоматически собирается с поддержкой OpenMAX IL, если обнаружит нужные хедеры в ```/opt/vc/include```. То же самое и с GPIO.
|
||||||
Порт для FreeBSD: https://www.freshports.org/multimedia/ustreamer.
|
Порт для FreeBSD: https://www.freshports.org/multimedia/ustreamer.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ license=(GPL)
|
|||||||
arch=(i686 x86_64 armv6h armv7h)
|
arch=(i686 x86_64 armv6h armv7h)
|
||||||
depends=(libjpeg libevent libutil-linux)
|
depends=(libjpeg libevent libutil-linux)
|
||||||
# optional: raspberrypi-firmware for OMX JPEG encoder
|
# optional: raspberrypi-firmware for OMX JPEG encoder
|
||||||
|
# optional: wiringpi for GPIO support
|
||||||
makedepends=(gcc make)
|
makedepends=(gcc make)
|
||||||
source=(${pkgname}::"git+https://github.com/pi-kvm/ustreamer#commit=v${pkgver}")
|
source=(${pkgname}::"git+https://github.com/pi-kvm/ustreamer#commit=v${pkgver}")
|
||||||
md5sums=(SKIP)
|
md5sums=(SKIP)
|
||||||
@@ -23,7 +24,8 @@ build() {
|
|||||||
cd $pkgname-build
|
cd $pkgname-build
|
||||||
|
|
||||||
local _options=""
|
local _options=""
|
||||||
[ -d /opt/vc/include ] && _options="$_options WITH_OMX_ENCODER=1"
|
[ -e /opt/vc/include/IL/OMX_Core.h ] && _options="$_options WITH_OMX_ENCODER=1"
|
||||||
|
[ -e /usr/include/wiringPi.h ] && _options="$_options WITH_GPIO=1"
|
||||||
|
|
||||||
make $_options CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" $MAKEFLAGS
|
make $_options CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" $MAKEFLAGS
|
||||||
}
|
}
|
||||||
|
|||||||
92
src/gpio.h
Normal file
92
src/gpio.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
# #
|
||||||
|
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||||
|
# #
|
||||||
|
# This program is free software: you can redistribute it and/or modify #
|
||||||
|
# it under the terms of the GNU General Public License as published by #
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or #
|
||||||
|
# (at your option) any later version. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||||
|
# GNU General Public License for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU General Public License #
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||||
|
# #
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <wiringPi.h>
|
||||||
|
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
|
||||||
|
int gpio_pin_prog_running;
|
||||||
|
int gpio_pin_stream_online;
|
||||||
|
int gpio_pin_has_http_clients;
|
||||||
|
int gpio_pin_workers_busy_at;
|
||||||
|
|
||||||
|
|
||||||
|
#define GPIO_INIT { \
|
||||||
|
gpio_pin_prog_running = -1; \
|
||||||
|
gpio_pin_stream_online = -1; \
|
||||||
|
gpio_pin_has_http_clients = -1; \
|
||||||
|
gpio_pin_workers_busy_at = -1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GPIO_INIT_PIN(_role, _offset) { \
|
||||||
|
if (gpio_pin_##_role >= 0) { \
|
||||||
|
pinMode(gpio_pin_##_role + _offset, OUTPUT); \
|
||||||
|
digitalWrite(gpio_pin_##_role + _offset, LOW); \
|
||||||
|
if (_offset == 0) { \
|
||||||
|
LOG_INFO("GPIO: Using pin %d as %s", gpio_pin_##_role, #_role); \
|
||||||
|
} else { \
|
||||||
|
LOG_INFO("GPIO: Using pin %d+%d as %s", gpio_pin_##_role, _offset, #_role); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GPIO_INIT_PINOUT { \
|
||||||
|
if ( \
|
||||||
|
gpio_pin_prog_running >= 0 \
|
||||||
|
|| gpio_pin_stream_online >= 0 \
|
||||||
|
|| gpio_pin_has_http_clients >= 0 \
|
||||||
|
|| gpio_pin_workers_busy_at >= 0 \
|
||||||
|
) { \
|
||||||
|
LOG_INFO("GPIO: Using wiringPi"); \
|
||||||
|
if (wiringPiSetupGpio() < 0) { \
|
||||||
|
LOG_PERROR("GPIO: Can't initialize wiringPi"); \
|
||||||
|
exit(1); \
|
||||||
|
} else { \
|
||||||
|
GPIO_INIT_PIN(prog_running, 0); \
|
||||||
|
GPIO_INIT_PIN(stream_online, 0); \
|
||||||
|
GPIO_INIT_PIN(has_http_clients, 0); \
|
||||||
|
GPIO_INIT_PIN(workers_busy_at, 0); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GPIO_SET_STATE(_role, _offset, _state) { \
|
||||||
|
if (gpio_pin_##_role >= 0) { \
|
||||||
|
if (_offset == 0) { \
|
||||||
|
LOG_DEBUG("GPIO: Writing %d to pin %d (%s)", _state, gpio_pin_##_role, #_role); \
|
||||||
|
} else { \
|
||||||
|
LOG_DEBUG("GPIO: Writing %d to pin %d+%d (%s)", _state, gpio_pin_##_role, _offset, #_role); \
|
||||||
|
} \
|
||||||
|
digitalWrite(gpio_pin_##_role + _offset, _state); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GPIO_SET_LOW(_role) GPIO_SET_STATE(_role, 0, LOW)
|
||||||
|
#define GPIO_SET_HIGH(_role) GPIO_SET_STATE(_role, 0, HIGH)
|
||||||
|
|
||||||
|
#define GPIO_SET_LOW_AT(_role, _offset) GPIO_SET_STATE(_role, _offset, LOW)
|
||||||
|
#define GPIO_SET_HIGH_AT(_role, _offset) GPIO_SET_STATE(_role, _offset, HIGH)
|
||||||
@@ -53,6 +53,9 @@
|
|||||||
#include "../logging.h"
|
#include "../logging.h"
|
||||||
#include "../encoder.h"
|
#include "../encoder.h"
|
||||||
#include "../stream.h"
|
#include "../stream.h"
|
||||||
|
#ifdef WITH_GPIO
|
||||||
|
# include "../gpio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "blank.h"
|
#include "blank.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
@@ -564,8 +567,14 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
|
|||||||
}
|
}
|
||||||
server->run->stream_clients_count += 1;
|
server->run->stream_clients_count += 1;
|
||||||
|
|
||||||
if (server->slowdown && server->run->stream_clients_count == 1) {
|
if (server->run->stream_clients_count == 1) {
|
||||||
stream_switch_slowdown(server->run->stream, false);
|
if (server->slowdown) {
|
||||||
|
stream_switch_slowdown(server->run->stream, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_HIGH(has_http_clients);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_connection_get_peer(conn, &client_addr, &client_port);
|
evhttp_connection_get_peer(conn, &client_addr, &client_port);
|
||||||
@@ -717,8 +726,15 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN
|
|||||||
# define RUN(_next) client->server->run->_next
|
# define RUN(_next) client->server->run->_next
|
||||||
|
|
||||||
RUN(stream_clients_count) -= 1;
|
RUN(stream_clients_count) -= 1;
|
||||||
if (client->server->slowdown && RUN(stream_clients_count) <= 0) {
|
|
||||||
stream_switch_slowdown(RUN(stream), true);
|
if (RUN(stream_clients_count) <= 0) {
|
||||||
|
if (client->server->slowdown) {
|
||||||
|
stream_switch_slowdown(RUN(stream), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_LOW(has_http_clients);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = evhttp_request_get_connection(client->request);
|
conn = evhttp_request_get_connection(client->request);
|
||||||
|
|||||||
51
src/main.c
51
src/main.c
@@ -32,10 +32,6 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#ifdef WITH_WORKERS_GPIO_DEBUG
|
|
||||||
# include <wiringPi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
@@ -43,6 +39,9 @@
|
|||||||
#include "encoder.h"
|
#include "encoder.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "http/server.h"
|
#include "http/server.h"
|
||||||
|
#ifdef WITH_GPIO
|
||||||
|
# include "gpio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const char _SHORT_OPTS[] = "d:i:x:y:m:a:f:z:ntb:w:q:c:s:p:u:ro:k:e:lhv";
|
static const char _SHORT_OPTS[] = "d:i:x:y:m:a:f:z:ntb:w:q:c:s:p:u:ro:k:e:lhv";
|
||||||
@@ -93,6 +92,13 @@ static const struct option _LONG_OPTS[] = {
|
|||||||
{"fake-height", required_argument, NULL, 3004},
|
{"fake-height", required_argument, NULL, 3004},
|
||||||
{"server-timeout", required_argument, NULL, 3005},
|
{"server-timeout", required_argument, NULL, 3005},
|
||||||
|
|
||||||
|
#ifdef WITH_GPIO
|
||||||
|
{"gpio-prog-running", required_argument, NULL, 4000},
|
||||||
|
{"gpio-stream-online", required_argument, NULL, 4001},
|
||||||
|
{"gpio-has-http-clients", required_argument, NULL, 4002},
|
||||||
|
{"gpio-workers-busy-at", required_argument, NULL, 4003},
|
||||||
|
#endif
|
||||||
|
|
||||||
{"perf", no_argument, NULL, 5000},
|
{"perf", no_argument, NULL, 5000},
|
||||||
{"verbose", no_argument, NULL, 5001},
|
{"verbose", no_argument, NULL, 5001},
|
||||||
{"debug", no_argument, NULL, 5002},
|
{"debug", no_argument, NULL, 5002},
|
||||||
@@ -183,6 +189,15 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
|
|||||||
printf(" --fake-width <N> ─────────── Override image width for /state. Default: disabled.\n\n");
|
printf(" --fake-width <N> ─────────── Override image width for /state. Default: disabled.\n\n");
|
||||||
printf(" --fake-height <N> ────────── Override image height for /state. Default: disabled.\n\n");
|
printf(" --fake-height <N> ────────── Override image height for /state. Default: disabled.\n\n");
|
||||||
printf(" --server-timeout <seconds> ─ Timeout for client connections. Default: %u.\n\n", server->timeout);
|
printf(" --server-timeout <seconds> ─ Timeout for client connections. Default: %u.\n\n", server->timeout);
|
||||||
|
#ifdef WITH_GPIO
|
||||||
|
printf("GPIO options:\n");
|
||||||
|
printf("═════════════\n");
|
||||||
|
printf(" --gpio-prog-running <pin> ───── Set 1 on GPIO pin while uStreamer is running. Default: disabled.\n\n");
|
||||||
|
printf(" --gpio-stream-online <pin> ──── Set 1 while streaming. Default: disabled\n\n");
|
||||||
|
printf(" --gpio-has-http-clients <pin> ─ Set 1 while stream has at least one client. Default: disabled.\n\n");
|
||||||
|
printf(" --gpio-workers-busy-at <pin> ── Set 1 on (pin + N) while worker with number N has a job.\n");
|
||||||
|
printf(" The workers numbering starts from zero. Default: disabled\n\n");
|
||||||
|
#endif
|
||||||
printf("Misc options:\n");
|
printf("Misc options:\n");
|
||||||
printf("═════════════\n");
|
printf("═════════════\n");
|
||||||
printf(" --log-level <N> ─ Verbosity level of messages from 0 (info) to 3 (debug).\n");
|
printf(" --log-level <N> ─ Verbosity level of messages from 0 (info) to 3 (debug).\n");
|
||||||
@@ -299,6 +314,13 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
|
|||||||
case 3004: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200);
|
case 3004: OPT_UNSIGNED(server->fake_height, "--fake-height", 0, 1200);
|
||||||
case 3005: OPT_UNSIGNED(server->timeout, "--server-timeout", 1, 60);
|
case 3005: OPT_UNSIGNED(server->timeout, "--server-timeout", 1, 60);
|
||||||
|
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
case 4000: OPT_UNSIGNED(gpio_pin_prog_running, "--gpio-prog-running", 0, 256);
|
||||||
|
case 4001: OPT_UNSIGNED(gpio_pin_stream_online, "--gpio-stream-online", 0, 256);
|
||||||
|
case 4002: OPT_UNSIGNED(gpio_pin_has_http_clients, "--gpio-has-http-clients", 0, 256);
|
||||||
|
case 4003: OPT_UNSIGNED(gpio_pin_workers_busy_at, "--gpio-workers-busy-at", 0, 256);
|
||||||
|
# endif
|
||||||
|
|
||||||
case 5000: OPT_SET(log_level, LOG_LEVEL_PERF);
|
case 5000: OPT_SET(log_level, LOG_LEVEL_PERF);
|
||||||
case 5001: OPT_SET(log_level, LOG_LEVEL_VERBOSE);
|
case 5001: OPT_SET(log_level, LOG_LEVEL_VERBOSE);
|
||||||
case 5002: OPT_SET(log_level, LOG_LEVEL_DEBUG);
|
case 5002: OPT_SET(log_level, LOG_LEVEL_DEBUG);
|
||||||
@@ -381,13 +403,8 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
LOGGING_INIT;
|
LOGGING_INIT;
|
||||||
|
|
||||||
# ifdef WITH_WORKERS_GPIO_DEBUG
|
# ifdef WITH_GPIO
|
||||||
if (wiringPiSetupGpio() < 0) {
|
GPIO_INIT;
|
||||||
LOG_PERROR("Can't initialize wiringPi GPIO");
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
LOG_INFO("Using wiringPi to debug using GPIO");
|
|
||||||
}
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
dev = device_init();
|
dev = device_init();
|
||||||
@@ -396,6 +413,10 @@ int main(int argc, char *argv[]) {
|
|||||||
server = http_server_init(stream);
|
server = http_server_init(stream);
|
||||||
|
|
||||||
if ((exit_code = _parse_options(argc, argv, dev, encoder, server)) == 0) {
|
if ((exit_code = _parse_options(argc, argv, dev, encoder, server)) == 0) {
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_INIT_PINOUT;
|
||||||
|
# endif
|
||||||
|
|
||||||
_install_signal_handlers();
|
_install_signal_handlers();
|
||||||
|
|
||||||
pthread_t stream_loop_tid;
|
pthread_t stream_loop_tid;
|
||||||
@@ -407,6 +428,10 @@ int main(int argc, char *argv[]) {
|
|||||||
_ctx = &ctx;
|
_ctx = &ctx;
|
||||||
|
|
||||||
if ((exit_code = http_server_listen(server)) == 0) {
|
if ((exit_code = http_server_listen(server)) == 0) {
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_HIGH(prog_running);
|
||||||
|
# endif
|
||||||
|
|
||||||
A_THREAD_CREATE(&stream_loop_tid, _stream_loop_thread, NULL);
|
A_THREAD_CREATE(&stream_loop_tid, _stream_loop_thread, NULL);
|
||||||
A_THREAD_CREATE(&server_loop_tid, _server_loop_thread, NULL);
|
A_THREAD_CREATE(&server_loop_tid, _server_loop_thread, NULL);
|
||||||
A_THREAD_JOIN(server_loop_tid);
|
A_THREAD_JOIN(server_loop_tid);
|
||||||
@@ -419,6 +444,10 @@ int main(int argc, char *argv[]) {
|
|||||||
encoder_destroy(encoder);
|
encoder_destroy(encoder);
|
||||||
device_destroy(dev);
|
device_destroy(dev);
|
||||||
|
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_LOW(prog_running);
|
||||||
|
# endif
|
||||||
|
|
||||||
LOGGING_DESTROY;
|
LOGGING_DESTROY;
|
||||||
return (exit_code < 0 ? 1 : 0);
|
return (exit_code < 0 ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/stream.c
49
src/stream.c
@@ -38,12 +38,8 @@
|
|||||||
#include "xioctl.h"
|
#include "xioctl.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "encoder.h"
|
#include "encoder.h"
|
||||||
|
#ifdef WITH_GPIO
|
||||||
#ifdef WITH_WORKERS_GPIO_DEBUG
|
# include "gpio.h"
|
||||||
# include <wiringPi.h>
|
|
||||||
# ifndef WORKERS_GPIO_DEBUG_START_PIN
|
|
||||||
# define WORKERS_GPIO_DEBUG_START_PIN 5
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -99,7 +95,7 @@ static void _stream_expose_picture(struct stream_t *stream, unsigned buf_index,
|
|||||||
static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream);
|
static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream);
|
||||||
static void _workers_pool_destroy(struct _workers_pool_t *pool);
|
static void _workers_pool_destroy(struct _workers_pool_t *pool);
|
||||||
|
|
||||||
static void *__worker_thread(void *v_worker);
|
static void *_worker_thread(void *v_worker);
|
||||||
|
|
||||||
static struct _worker_t *_workers_pool_wait(struct _workers_pool_t *pool);
|
static struct _worker_t *_workers_pool_wait(struct _workers_pool_t *pool);
|
||||||
static void _workers_pool_assign(struct _workers_pool_t *pool, struct _worker_t *ready_worker, unsigned buf_index);
|
static void _workers_pool_assign(struct _workers_pool_t *pool, struct _worker_t *ready_worker, unsigned buf_index);
|
||||||
@@ -187,11 +183,16 @@ void stream_loop(struct stream_t *stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (selected == 0) {
|
} else if (selected == 0) {
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_LOW(stream_online);
|
||||||
|
# endif
|
||||||
|
|
||||||
if (stream->dev->persistent) {
|
if (stream->dev->persistent) {
|
||||||
if (!persistent_timeout_reported) {
|
if (!persistent_timeout_reported) {
|
||||||
LOG_ERROR("Mainloop select() timeout, polling ...")
|
LOG_ERROR("Mainloop select() timeout, polling ...")
|
||||||
persistent_timeout_reported = true;
|
persistent_timeout_reported = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Mainloop select() timeout");
|
LOG_ERROR("Mainloop select() timeout");
|
||||||
@@ -204,6 +205,10 @@ void stream_loop(struct stream_t *stream) {
|
|||||||
if (has_read) {
|
if (has_read) {
|
||||||
LOG_DEBUG("Frame is ready");
|
LOG_DEBUG("Frame is ready");
|
||||||
|
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_HIGH(stream_online);
|
||||||
|
# endif
|
||||||
|
|
||||||
int buf_index;
|
int buf_index;
|
||||||
long double now = get_now_monotonic();
|
long double now = get_now_monotonic();
|
||||||
long long now_second = floor_ms(now);
|
long long now_second = floor_ms(now);
|
||||||
@@ -283,6 +288,10 @@ void stream_loop(struct stream_t *stream) {
|
|||||||
_workers_pool_destroy(pool);
|
_workers_pool_destroy(pool);
|
||||||
device_switch_capturing(stream->dev, false);
|
device_switch_capturing(stream->dev, false);
|
||||||
device_close(stream->dev);
|
device_close(stream->dev);
|
||||||
|
|
||||||
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_LOW(stream_online);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +398,7 @@ static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream) {
|
|||||||
WORKER(dev) = stream->dev;
|
WORKER(dev) = stream->dev;
|
||||||
WORKER(encoder) = stream->encoder;
|
WORKER(encoder) = stream->encoder;
|
||||||
|
|
||||||
A_THREAD_CREATE(&WORKER(tid), __worker_thread, (void *)&(pool->workers[number]));
|
A_THREAD_CREATE(&WORKER(tid), _worker_thread, (void *)&(pool->workers[number]));
|
||||||
|
|
||||||
pool->free_workers += 1;
|
pool->free_workers += 1;
|
||||||
|
|
||||||
@@ -424,25 +433,21 @@ static void _workers_pool_destroy(struct _workers_pool_t *pool) {
|
|||||||
free(pool);
|
free(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *__worker_thread(void *v_worker) {
|
static void *_worker_thread(void *v_worker) {
|
||||||
struct _worker_t *worker = (struct _worker_t *)v_worker;
|
struct _worker_t *worker = (struct _worker_t *)v_worker;
|
||||||
|
|
||||||
LOG_DEBUG("Hello! I am a worker #%u ^_^", worker->number);
|
LOG_DEBUG("Hello! I am a worker #%u ^_^", worker->number);
|
||||||
|
|
||||||
# ifdef WITH_WORKERS_GPIO_DEBUG
|
# ifdef WITH_GPIO
|
||||||
# define WORKER_GPIO_DEBUG_BUSY digitalWrite(WORKERS_GPIO_DEBUG_START_PIN + worker->number, HIGH)
|
GPIO_INIT_PIN(workers_busy_at, worker->number);
|
||||||
# define WORKER_GPIO_DEBUG_FREE digitalWrite(WORKERS_GPIO_DEBUG_START_PIN + worker->number, LOW)
|
|
||||||
pinMode(WORKERS_GPIO_DEBUG_START_PIN + worker->number, OUTPUT);
|
|
||||||
WORKER_GPIO_DEBUG_FREE;
|
|
||||||
# else
|
|
||||||
# define WORKER_GPIO_DEBUG_BUSY
|
|
||||||
# define WORKER_GPIO_DEBUG_FREE
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
while (!atomic_load(worker->proc_stop) && !atomic_load(worker->workers_stop)) {
|
while (!atomic_load(worker->proc_stop) && !atomic_load(worker->workers_stop)) {
|
||||||
LOG_DEBUG("Worker %u waiting for a new job ...", worker->number);
|
LOG_DEBUG("Worker %u waiting for a new job ...", worker->number);
|
||||||
|
|
||||||
WORKER_GPIO_DEBUG_FREE;
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_LOW_AT(workers_busy_at, worker->number);
|
||||||
|
# endif
|
||||||
|
|
||||||
A_MUTEX_LOCK(&worker->has_job_mutex);
|
A_MUTEX_LOCK(&worker->has_job_mutex);
|
||||||
A_COND_WAIT_TRUE(atomic_load(&worker->has_job), &worker->has_job_cond, &worker->has_job_mutex);
|
A_COND_WAIT_TRUE(atomic_load(&worker->has_job), &worker->has_job_cond, &worker->has_job_mutex);
|
||||||
@@ -453,7 +458,9 @@ static void *__worker_thread(void *v_worker) {
|
|||||||
|
|
||||||
LOG_DEBUG("Worker %u compressing JPEG from buffer %u ...", worker->number, worker->buf_index);
|
LOG_DEBUG("Worker %u compressing JPEG from buffer %u ...", worker->number, worker->buf_index);
|
||||||
|
|
||||||
WORKER_GPIO_DEBUG_BUSY;
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_HIGH_AT(workers_busy_at, worker->number);
|
||||||
|
# endif
|
||||||
|
|
||||||
if (encoder_compress_buffer(worker->encoder, worker->dev, worker->number, worker->buf_index) < 0) {
|
if (encoder_compress_buffer(worker->encoder, worker->dev, worker->number, worker->buf_index) < 0) {
|
||||||
worker->job_failed = false;
|
worker->job_failed = false;
|
||||||
@@ -482,7 +489,9 @@ static void *__worker_thread(void *v_worker) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Bye-bye (worker %u)", worker->number);
|
LOG_DEBUG("Bye-bye (worker %u)", worker->number);
|
||||||
WORKER_GPIO_DEBUG_FREE;
|
# ifdef WITH_GPIO
|
||||||
|
GPIO_SET_LOW_AT(workers_busy_at, worker->number);
|
||||||
|
# endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user