mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-02-27 20:26:31 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83127e58ff | ||
|
|
604a8f7cb4 | ||
|
|
602c1747d5 | ||
|
|
a2b8b35070 | ||
|
|
dd7701be38 | ||
|
|
1c9bd91b31 | ||
|
|
e19a3ca7ff | ||
|
|
b2d1a5612d | ||
|
|
f3e0613de3 | ||
|
|
5baf921660 | ||
|
|
6cabcd39f1 | ||
|
|
3df3658e4f | ||
|
|
f21fc5f6d3 | ||
|
|
b70ed98af9 | ||
|
|
52cdabe150 | ||
|
|
fe86997d08 | ||
|
|
df39b824c6 | ||
|
|
db297db52e | ||
|
|
b304364af9 | ||
|
|
ddec4e8478 | ||
|
|
28ca658621 | ||
|
|
270d3ae3a9 | ||
|
|
c1f080f29f |
@@ -1,7 +1,7 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
commit = True
|
commit = True
|
||||||
tag = True
|
tag = True
|
||||||
current_version = 6.25
|
current_version = 6.32
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)
|
||||||
serialize =
|
serialize =
|
||||||
{major}.{minor}
|
{major}.{minor}
|
||||||
|
|||||||
41
Makefile
41
Makefile
@@ -1,43 +1,64 @@
|
|||||||
-include config.mk
|
-include config.mk
|
||||||
|
|
||||||
|
|
||||||
|
# =====
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
MANPREFIX ?= $(PREFIX)/share/man
|
MANPREFIX ?= $(PREFIX)/share/man
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
PY ?= python3
|
PY ?= python3
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
CFLAGS ?= -O3
|
CFLAGS ?= -O3
|
||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
|
|
||||||
R_DESTDIR = $(if $(DESTDIR),$(shell realpath "$(DESTDIR)"),)
|
R_DESTDIR = $(if $(DESTDIR),$(shell realpath "$(DESTDIR)"),)
|
||||||
|
|
||||||
|
WITH_PYTHON ?= 0
|
||||||
|
WITH_JANUS ?= 0
|
||||||
|
WITH_V4P ?= 0
|
||||||
|
WITH_GPIO ?= 0
|
||||||
|
WITH_SYSTEMD ?= 0
|
||||||
|
WITH_PTHREAD_NP ?= 1
|
||||||
|
WITH_SETPROCTITLE ?= 1
|
||||||
|
WITH_PDEATHSIG ?= 1
|
||||||
|
|
||||||
|
define optbool
|
||||||
|
$(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
|
||||||
|
endef
|
||||||
|
MK_WITH_PYTHON = $(call optbool,$(WITH_PYTHON))
|
||||||
|
MK_WITH_JANUS = $(call optbool,$(WITH_JANUS))
|
||||||
|
MK_WITH_V4P = $(call optbool,$(WITH_V4P))
|
||||||
|
MK_WITH_GPIO = $(call optbool,$(WITH_GPIO))
|
||||||
|
MK_WITH_SYSTEMD = $(call optbool,$(WITH_SYSTEMD))
|
||||||
|
MK_WITH_PTHREAD_NP = $(call optbool,$(WITH_PTHREAD_NP))
|
||||||
|
MK_WITH_SETPROCTITLE = $(call optbool,$(WITH_SETPROCTITLE))
|
||||||
|
MK_WITH_PDEATHSIG = $(call optbool,$(WITH_PDEATHSIG))
|
||||||
|
|
||||||
export
|
export
|
||||||
|
|
||||||
_LINTERS_IMAGE ?= ustreamer-linters
|
_LINTERS_IMAGE ?= ustreamer-linters
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
ifeq (__not_found__,$(shell which pkg-config 2>/dev/null || echo "__not_found__"))
|
ifeq (__not_found__,$(shell which $(PKG_CONFIG) 2>/dev/null || echo "__not_found__"))
|
||||||
$(error "No pkg-config found in $(PATH)")
|
$(error "No $(PKG_CONFIG) found in $(PATH)")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
define optbool
|
|
||||||
$(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
|
|
||||||
endef
|
|
||||||
|
|
||||||
ifeq ($(V),)
|
ifeq ($(V),)
|
||||||
ECHO = @
|
ECHO = @
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
all:
|
all:
|
||||||
+ $(MAKE) apps
|
+ $(MAKE) apps
|
||||||
ifneq ($(call optbool,$(WITH_PYTHON)),)
|
ifneq ($(MK_WITH_PYTHON),)
|
||||||
+ $(MAKE) python
|
+ $(MAKE) python
|
||||||
endif
|
endif
|
||||||
ifneq ($(call optbool,$(WITH_JANUS)),)
|
ifneq ($(MK_WITH_JANUS),)
|
||||||
+ $(MAKE) janus
|
+ $(MAKE) janus
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -61,10 +82,10 @@ janus:
|
|||||||
|
|
||||||
install: all
|
install: all
|
||||||
$(MAKE) -C src install
|
$(MAKE) -C src install
|
||||||
ifneq ($(call optbool,$(WITH_PYTHON)),)
|
ifneq ($(MK_WITH_PYTHON),)
|
||||||
$(MAKE) -C python install
|
$(MAKE) -C python install
|
||||||
endif
|
endif
|
||||||
ifneq ($(call optbool,$(WITH_JANUS)),)
|
ifneq ($(MK_WITH_JANUS),)
|
||||||
$(MAKE) -C janus install
|
$(MAKE) -C janus install
|
||||||
endif
|
endif
|
||||||
mkdir -p $(R_DESTDIR)$(MANPREFIX)/man1
|
mkdir -p $(R_DESTDIR)$(MANPREFIX)/man1
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ R_DESTDIR ?=
|
|||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
CFLAGS ?= -O3
|
CFLAGS ?= -O3
|
||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
|
|
||||||
@@ -9,21 +10,15 @@ LDFLAGS ?=
|
|||||||
# =====
|
# =====
|
||||||
_PLUGIN = libjanus_ustreamer.so
|
_PLUGIN = libjanus_ustreamer.so
|
||||||
|
|
||||||
_CFLAGS = -fPIC -MD -c -std=c17 -Wall -Wextra -D_GNU_SOURCE $(shell pkg-config --cflags glib-2.0) $(CFLAGS)
|
_CFLAGS = -fPIC -MD -c -std=c17 -Wall -Wextra -D_GNU_SOURCE $(shell $(PKG_CONFIG) --cflags glib-2.0) $(CFLAGS)
|
||||||
_LDFLAGS = -shared -lm -pthread -lrt -ljansson -lopus -lasound -lspeexdsp $(shell pkg-config --libs glib-2.0) $(LDFLAGS)
|
_LDFLAGS = -shared -lm -pthread -lrt -ljansson -lopus -lasound -lspeexdsp $(shell $(PKG_CONFIG) --libs glib-2.0) $(LDFLAGS)
|
||||||
|
|
||||||
_SRCS = $(shell ls src/uslibs/*.c src/*.c)
|
_SRCS = $(shell ls src/uslibs/*.c src/*.c)
|
||||||
|
|
||||||
_BUILD = build
|
_BUILD = build
|
||||||
|
|
||||||
|
|
||||||
define optbool
|
ifneq ($(MK_WITH_PTHREAD_NP),)
|
||||||
$(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
|
|
||||||
endef
|
|
||||||
|
|
||||||
|
|
||||||
WITH_PTHREAD_NP ?= 1
|
|
||||||
ifneq ($(call optbool,$(WITH_PTHREAD_NP)),)
|
|
||||||
override _CFLAGS += -DWITH_PTHREAD_NP
|
override _CFLAGS += -DWITH_PTHREAD_NP
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -205,8 +205,15 @@ static void *_video_or_acap_thread(void *v_client, bool video) {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
if (rtp.video) {
|
if (rtp.video) {
|
||||||
const uint video_orient = atomic_load(&client->video_orient);
|
uint video_orient = atomic_load(&client->video_orient);
|
||||||
if (video_orient != 0) {
|
if (video_orient != 0) {
|
||||||
|
// The extension rotates the video clockwise, but want it counterclockwise.
|
||||||
|
// It's more intuitive for people who have seen a protractor at least once in their life.
|
||||||
|
if (video_orient == 90) {
|
||||||
|
video_orient = 270;
|
||||||
|
} else if (video_orient == 270) {
|
||||||
|
video_orient = 90;
|
||||||
|
}
|
||||||
packet.extensions.video_rotation = video_orient;
|
packet.extensions.video_rotation = video_orient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <janus/config.h>
|
#include <janus/config.h>
|
||||||
#include <janus/plugins/plugin.h>
|
#include <janus/plugins/plugin.h>
|
||||||
@@ -64,7 +65,16 @@ us_config_s *us_config_init(const char *config_dir_path) {
|
|||||||
US_JLOG_INFO("config", "Missing config value: acap.tc358743");
|
US_JLOG_INFO("config", "Missing config value: acap.tc358743");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
config->aplay_dev_name = _get_value(jcfg, "aplay", "device");
|
if ((config->aplay_dev_name = _get_value(jcfg, "aplay", "device")) != NULL) {
|
||||||
|
char *path = _get_value(jcfg, "aplay", "check");
|
||||||
|
if (path != NULL) {
|
||||||
|
if (access(path, F_OK) != 0) {
|
||||||
|
US_JLOG_INFO("config", "No check file found, aplay will be disabled");
|
||||||
|
US_DELETE(config->aplay_dev_name, free);
|
||||||
|
}
|
||||||
|
US_DELETE(path, free);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
goto ok;
|
goto ok;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
#include "memsinkfd.h"
|
#include "memsinkfd.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
static us_config_s *_g_config = NULL;
|
static us_config_s *_g_config = NULL;
|
||||||
static const useconds_t _g_watchers_polling = 100000;
|
static const useconds_t _g_watchers_polling = 100000;
|
||||||
|
|
||||||
@@ -669,10 +670,15 @@ static struct janus_plugin_result *_plugin_handle_message(
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (!strcmp(request_str, "features")) {
|
} else if (!strcmp(request_str, "features")) {
|
||||||
|
const char *const stun_host = getenv("JANUS_USTREAMER_STUN_HOST");
|
||||||
|
const char *const stun_port = getenv("JANUS_USTREAMER_STUN_PORT");
|
||||||
json_t *const features = json_pack(
|
json_t *const features = json_pack(
|
||||||
"{sbsb}",
|
"{s:b, s:b, s:{s:s, s:i}}",
|
||||||
"audio", (_g_rtpa != NULL),
|
"audio", (_g_rtpa != NULL),
|
||||||
"mic", (_g_rtpa != NULL && _g_config->aplay_dev_name != NULL)
|
"mic", (_g_rtpa != NULL && _g_config->aplay_dev_name != NULL),
|
||||||
|
"stun",
|
||||||
|
"host", (stun_host != NULL ? stun_host : ""),
|
||||||
|
"port", (stun_port != NULL ? atoi(stun_port) : 0)
|
||||||
);
|
);
|
||||||
PUSH_STATUS("features", features, NULL);
|
PUSH_STATUS("features", features, NULL);
|
||||||
json_decref(features);
|
json_decref(features);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer-dump.
|
.\" Manpage for ustreamer-dump.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER-DUMP 1 "version 6.25" "January 2021"
|
.TH USTREAMER-DUMP 1 "version 6.32" "January 2021"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer-dump \- Dump uStreamer's memory sink to file
|
ustreamer-dump \- Dump uStreamer's memory sink to file
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Manpage for ustreamer.
|
.\" Manpage for ustreamer.
|
||||||
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
|
||||||
.TH USTREAMER 1 "version 6.25" "November 2020"
|
.TH USTREAMER 1 "version 6.32" "November 2020"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
ustreamer \- stream MJPEG video from any V4L2 device to the network
|
||||||
@@ -52,7 +52,7 @@ Initial image resolution. Default: 640x480.
|
|||||||
.TP
|
.TP
|
||||||
.BR \-m\ \fIfmt ", " \-\-format\ \fIfmt
|
.BR \-m\ \fIfmt ", " \-\-format\ \fIfmt
|
||||||
Image format.
|
Image format.
|
||||||
Available: YUYV, YVYU, UYVY, RGB565, RGB24, JPEG; default: YUYV.
|
Available: YUYV, YVYU, UYVY, YUV420, YVU420, RGB565, RGB24, JPEG; default: YUYV.
|
||||||
.TP
|
.TP
|
||||||
.BR \-a\ \fIstd ", " \-\-tv\-standard\ \fIstd
|
.BR \-a\ \fIstd ", " \-\-tv\-standard\ \fIstd
|
||||||
Force TV standard.
|
Force TV standard.
|
||||||
@@ -274,7 +274,7 @@ Timeout for lock. Default: 1.
|
|||||||
.SS "Process options"
|
.SS "Process options"
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-exit\-on\-parent\-death
|
.BR \-\-exit\-on\-parent\-death
|
||||||
Exit the program if the parent process is dead. Required \fBHAS_PDEATHSIG\fR feature. Default: disabled.
|
Exit the program if the parent process is dead. Required \fBWITH_PDEATHSIG\fR feature. Default: disabled.
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-exit\-on\-no\-clients \fIsec
|
.BR \-\-exit\-on\-no\-clients \fIsec
|
||||||
Exit the program if there have been no stream or sink clients or any HTTP requests in the last N seconds. Default: 0 (disabled).
|
Exit the program if there have been no stream or sink clients or any HTTP requests in the last N seconds. Default: 0 (disabled).
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
pkgname=ustreamer
|
pkgname=ustreamer
|
||||||
pkgver=6.25
|
pkgver=6.32
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
|
||||||
url="https://github.com/pikvm/ustreamer"
|
url="https://github.com/pikvm/ustreamer"
|
||||||
@@ -18,7 +18,7 @@ md5sums=(SKIP)
|
|||||||
_options="WITH_GPIO=1 WITH_SYSTEMD=1"
|
_options="WITH_GPIO=1 WITH_SYSTEMD=1"
|
||||||
if [ -e /usr/bin/python3 ]; then
|
if [ -e /usr/bin/python3 ]; then
|
||||||
_options="$_options WITH_PYTHON=1"
|
_options="$_options WITH_PYTHON=1"
|
||||||
depends+=(python)
|
depends+=("python>=3.13" "python<3.14")
|
||||||
makedepends+=(python-setuptools python-pip python-build python-wheel)
|
makedepends+=(python-setuptools python-pip python-build python-wheel)
|
||||||
fi
|
fi
|
||||||
if [ -e /usr/include/janus/plugins/plugin.h ];then
|
if [ -e /usr/include/janus/plugins/plugin.h ];then
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=ustreamer
|
PKG_NAME:=ustreamer
|
||||||
PKG_VERSION:=6.25
|
PKG_VERSION:=6.32
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
-include ../config.mk
|
|
||||||
|
|
||||||
R_DESTDIR ?=
|
R_DESTDIR ?=
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
@@ -8,7 +6,7 @@ PY ?= python3
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
all: root
|
all: root
|
||||||
root: $(shell find src -type f,l)
|
root: $(shell find src -type f,l) setup.py
|
||||||
$(info == PY_BUILD ustreamer-*.so)
|
$(info == PY_BUILD ustreamer-*.so)
|
||||||
rm -rf root
|
rm -rf root
|
||||||
$(ECHO) $(PY) -m build --skip-dependency-check --no-isolation
|
$(ECHO) $(PY) -m build --skip-dependency-check --no-isolation
|
||||||
|
|||||||
@@ -5,19 +5,36 @@ from setuptools import setup
|
|||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
def _find_sources(suffix: str) -> list[str]:
|
def _find_sources() -> list[str]:
|
||||||
sources: list[str] = []
|
sources: list[str] = []
|
||||||
for (root_path, _, names) in os.walk("src"):
|
for (root_path, _, names) in os.walk("src"):
|
||||||
for name in names:
|
for name in names:
|
||||||
if name.endswith(suffix):
|
if name.endswith(".c"):
|
||||||
sources.append(os.path.join(root_path, name))
|
sources.append(os.path.join(root_path, name))
|
||||||
return sources
|
return sources
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def _find_flags() -> dict[str, bool]:
|
||||||
|
return {
|
||||||
|
key[3:]: (value.strip().lower() in ["true", "on", "1"])
|
||||||
|
for (key, value) in sorted(os.environ.items())
|
||||||
|
if key.startswith("MK_WITH_")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _make_d_features(flags: dict[str, bool]) -> str:
|
||||||
|
features = " ".join([
|
||||||
|
f"{key}={int(value)}"
|
||||||
|
for (key, value) in flags.items()
|
||||||
|
])
|
||||||
|
return f"-DUS_FEATURES=\"{features}\""
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
flags = _find_flags()
|
||||||
setup(
|
setup(
|
||||||
name="ustreamer",
|
name="ustreamer",
|
||||||
version="6.25",
|
version="6.32",
|
||||||
description="uStreamer tools",
|
description="uStreamer tools",
|
||||||
author="Maxim Devaev",
|
author="Maxim Devaev",
|
||||||
author_email="mdevaev@gmail.com",
|
author_email="mdevaev@gmail.com",
|
||||||
@@ -26,9 +43,16 @@ if __name__ == "__main__":
|
|||||||
Extension(
|
Extension(
|
||||||
"ustreamer",
|
"ustreamer",
|
||||||
libraries=["rt", "m", "pthread"],
|
libraries=["rt", "m", "pthread"],
|
||||||
extra_compile_args=["-std=c17", "-D_GNU_SOURCE"],
|
extra_compile_args=[
|
||||||
|
"-std=c17", "-D_GNU_SOURCE",
|
||||||
|
_make_d_features(flags),
|
||||||
|
],
|
||||||
undef_macros=["NDEBUG"],
|
undef_macros=["NDEBUG"],
|
||||||
sources=_find_sources(".c"),
|
sources=_find_sources(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
1
python/src/uslibs/const.h
Symbolic link
1
python/src/uslibs/const.h
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../src/libs/const.h
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include "uslibs/const.h"
|
||||||
#include "uslibs/types.h"
|
#include "uslibs/types.h"
|
||||||
#include "uslibs/errors.h"
|
#include "uslibs/errors.h"
|
||||||
#include "uslibs/tools.h"
|
#include "uslibs/tools.h"
|
||||||
@@ -48,6 +49,8 @@ static void _MemsinkObject_destroy_internals(_MemsinkObject *self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *kwargs) {
|
static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *kwargs) {
|
||||||
|
self->fd = -1;
|
||||||
|
|
||||||
self->lock_timeout = 1;
|
self->lock_timeout = 1;
|
||||||
self->wait_timeout = 1;
|
self->wait_timeout = 1;
|
||||||
|
|
||||||
@@ -228,7 +231,8 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args,
|
|||||||
} \
|
} \
|
||||||
Py_DECREF(m_tmp); \
|
Py_DECREF(m_tmp); \
|
||||||
}
|
}
|
||||||
# define SET_NUMBER(x_key, x_from, x_to) SET_VALUE(#x_key, Py##x_to##_From##x_from(self->frame->x_key))
|
# define SET_NUMBER(x_key, x_from, x_to) \
|
||||||
|
SET_VALUE(#x_key, Py##x_to##_From##x_from(self->frame->x_key))
|
||||||
|
|
||||||
SET_NUMBER(width, Long, Long);
|
SET_NUMBER(width, Long, Long);
|
||||||
SET_NUMBER(height, Long, Long);
|
SET_NUMBER(height, Long, Long);
|
||||||
@@ -275,7 +279,8 @@ static PyMethodDef _MemsinkObject_methods[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PyGetSetDef _MemsinkObject_getsets[] = {
|
static PyGetSetDef _MemsinkObject_getsets[] = {
|
||||||
# define ADD_GETTER(x_field) {.name = #x_field, .get = (getter)_MemsinkObject_getter_##x_field}
|
# define ADD_GETTER(x_field) \
|
||||||
|
{.name = #x_field, .get = (getter)_MemsinkObject_getter_##x_field}
|
||||||
ADD_GETTER(obj),
|
ADD_GETTER(obj),
|
||||||
ADD_GETTER(lock_timeout),
|
ADD_GETTER(lock_timeout),
|
||||||
ADD_GETTER(wait_timeout),
|
ADD_GETTER(wait_timeout),
|
||||||
@@ -304,20 +309,30 @@ static PyModuleDef _Module = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC PyInit_ustreamer(void) {
|
PyMODINIT_FUNC PyInit_ustreamer(void) {
|
||||||
PyObject *module = PyModule_Create(&_Module);
|
PyObject *module = NULL;
|
||||||
if (module == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyType_Ready(&_MemsinkType) < 0) {
|
if (PyType_Ready(&_MemsinkType) < 0) {
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_INCREF(&_MemsinkType);
|
if ((module = PyModule_Create(&_Module)) == NULL) {
|
||||||
|
goto error;
|
||||||
if (PyModule_AddObject(module, "Memsink", (PyObject*)&_MemsinkType) < 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# define ADD(x_what, x_key, x_value) \
|
||||||
|
{ if (PyModule_Add##x_what(module, x_key, x_value) < 0) { goto error; } }
|
||||||
|
ADD(StringConstant, "__version__", US_VERSION);
|
||||||
|
ADD(StringConstant, "VERSION", US_VERSION);
|
||||||
|
ADD(IntConstant, "VERSION_MAJOR", US_VERSION_MAJOR);
|
||||||
|
ADD(IntConstant, "VERSION_MINOR", US_VERSION_MINOR);
|
||||||
|
ADD(StringConstant, "FEATURES", US_FEATURES); // Defined in setup.py
|
||||||
|
ADD(ObjectRef, "Memsink", (PyObject*)&_MemsinkType);
|
||||||
|
# undef ADD
|
||||||
return module;
|
return module;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (module != NULL) {
|
||||||
|
Py_DECREF(module);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/Makefile
45
src/Makefile
@@ -2,6 +2,7 @@ R_DESTDIR ?=
|
|||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
|
PKG_CONFIG ?= pkg-config
|
||||||
CFLAGS ?= -O3
|
CFLAGS ?= -O3
|
||||||
LDFLAGS ?=
|
LDFLAGS ?=
|
||||||
|
|
||||||
@@ -40,53 +41,53 @@ _V4P_SRCS = $(shell ls \
|
|||||||
|
|
||||||
_BUILD = build
|
_BUILD = build
|
||||||
|
|
||||||
|
|
||||||
_TARGETS = $(_USTR) $(_DUMP)
|
_TARGETS = $(_USTR) $(_DUMP)
|
||||||
_OBJS = $(_USTR_SRCS:%.c=$(_BUILD)/%.o) $(_DUMP_SRCS:%.c=$(_BUILD)/%.o)
|
_OBJS = $(_USTR_SRCS:%.c=$(_BUILD)/%.o) $(_DUMP_SRCS:%.c=$(_BUILD)/%.o)
|
||||||
|
|
||||||
|
|
||||||
define optbool
|
# =====
|
||||||
$(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
|
ifneq ($(MK_WITH_PYTHON),)
|
||||||
endef
|
override _CFLAGS += -DMK_WITH_PYTHON
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(MK_WITH_JANUS),)
|
||||||
|
override _CFLAGS += -DMK_WITH_JANUS
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(call optbool,$(WITH_GPIO)),)
|
ifneq ($(MK_WITH_GPIO),)
|
||||||
override _CFLAGS += -DWITH_GPIO $(shell pkg-config --atleast-version=2 libgpiod 2> /dev/null && echo -DHAVE_GPIOD2)
|
override _CFLAGS += -DMK_WITH_GPIO -DWITH_GPIO $(shell $(PKG_CONFIG) --atleast-version=2 libgpiod 2> /dev/null && echo -DHAVE_GPIOD2)
|
||||||
override _USTR_LDFLAGS += -lgpiod
|
override _USTR_LDFLAGS += -lgpiod
|
||||||
override _USTR_SRCS += $(shell ls ustreamer/gpio/*.c)
|
override _USTR_SRCS += $(shell ls ustreamer/gpio/*.c)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(MK_WITH_SYSTEMD),)
|
||||||
ifneq ($(call optbool,$(WITH_SYSTEMD)),)
|
override _CFLAGS += -DMK_WITH_SYSTEMD -DWITH_SYSTEMD
|
||||||
override _CFLAGS += -DWITH_SYSTEMD
|
|
||||||
override _USTR_LDFLAGS += -lsystemd
|
override _USTR_LDFLAGS += -lsystemd
|
||||||
override _USTR_SRCS += $(shell ls ustreamer/http/systemd/*.c)
|
override _USTR_SRCS += $(shell ls ustreamer/http/systemd/*.c)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(MK_WITH_PTHREAD_NP),)
|
||||||
WITH_PTHREAD_NP ?= 1
|
override _CFLAGS += -DMK_WITH_PTHREAD_NP -DWITH_PTHREAD_NP
|
||||||
ifneq ($(call optbool,$(WITH_PTHREAD_NP)),)
|
|
||||||
override _CFLAGS += -DWITH_PTHREAD_NP
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(MK_WITH_SETPROCTITLE),)
|
||||||
WITH_SETPROCTITLE ?= 1
|
override _CFLAGS += -DMK_WITH_SETPROCTITLE -DWITH_SETPROCTITLE
|
||||||
ifneq ($(call optbool,$(WITH_SETPROCTITLE)),)
|
|
||||||
override _CFLAGS += -DWITH_SETPROCTITLE
|
|
||||||
ifeq ($(shell uname -s | tr A-Z a-z),linux)
|
ifeq ($(shell uname -s | tr A-Z a-z),linux)
|
||||||
override _USTR_LDFLAGS += -lbsd
|
override _USTR_LDFLAGS += -lbsd
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(MK_WITH_PDEATHSIG),)
|
||||||
|
override _CFLAGS += -DMK_WITH_PDEATHSIG -DWITH_PDEATHSIG
|
||||||
|
endif
|
||||||
|
|
||||||
WITH_V4P ?= 0
|
ifneq ($(MK_WITH_V4P),)
|
||||||
ifneq ($(call optbool,$(WITH_V4P)),)
|
|
||||||
override _TARGETS += $(_V4P)
|
override _TARGETS += $(_V4P)
|
||||||
override _OBJS += $(_V4P_SRCS:%.c=$(_BUILD)/%.o)
|
override _OBJS += $(_V4P_SRCS:%.c=$(_BUILD)/%.o)
|
||||||
override _CFLAGS += -DWITH_V4P $(shell pkg-config --cflags libdrm)
|
override _CFLAGS += -DMK_WITH_V4P -DWITH_V4P $(shell $(PKG_CONFIG) --cflags libdrm)
|
||||||
override _V4P_LDFLAGS += $(shell pkg-config --libs libdrm)
|
override _V4P_LDFLAGS += $(shell $(PKG_CONFIG) --libs libdrm)
|
||||||
override _USTR_SRCS += $(shell ls libs/drm/*.c)
|
override _USTR_SRCS += $(shell ls libs/drm/*.c)
|
||||||
override _USTR_LDFLAGS += $(shell pkg-config --libs libdrm)
|
override _USTR_LDFLAGS += $(shell $(PKG_CONFIG) --libs libdrm)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ static const struct {
|
|||||||
{"YUYV", V4L2_PIX_FMT_YUYV},
|
{"YUYV", V4L2_PIX_FMT_YUYV},
|
||||||
{"YVYU", V4L2_PIX_FMT_YVYU},
|
{"YVYU", V4L2_PIX_FMT_YVYU},
|
||||||
{"UYVY", V4L2_PIX_FMT_UYVY},
|
{"UYVY", V4L2_PIX_FMT_UYVY},
|
||||||
|
{"YUV420", V4L2_PIX_FMT_YUV420},
|
||||||
|
{"YVU420", V4L2_PIX_FMT_YVU420},
|
||||||
{"RGB565", V4L2_PIX_FMT_RGB565},
|
{"RGB565", V4L2_PIX_FMT_RGB565},
|
||||||
{"RGB24", V4L2_PIX_FMT_RGB24},
|
{"RGB24", V4L2_PIX_FMT_RGB24},
|
||||||
{"BGR24", V4L2_PIX_FMT_BGR24},
|
{"BGR24", V4L2_PIX_FMT_BGR24},
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
#define US_VIDEO_MAX_FPS ((uint)120)
|
#define US_VIDEO_MAX_FPS ((uint)120)
|
||||||
|
|
||||||
#define US_STANDARDS_STR "PAL, NTSC, SECAM"
|
#define US_STANDARDS_STR "PAL, NTSC, SECAM"
|
||||||
#define US_FORMATS_STR "YUYV, YVYU, UYVY, RGB565, RGB24, BGR24, MJPEG, JPEG"
|
#define US_FORMATS_STR "YUYV, YVYU, UYVY, YUV420, YVU420, RGB565, RGB24, BGR24, MJPEG, JPEG"
|
||||||
#define US_IO_METHODS_STR "MMAP, USERPTR"
|
#define US_IO_METHODS_STR "MMAP, USERPTR"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define US_VERSION_MAJOR 6
|
#define US_VERSION_MAJOR 6
|
||||||
#define US_VERSION_MINOR 25
|
#define US_VERSION_MINOR 32
|
||||||
|
|
||||||
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
|
||||||
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)
|
||||||
|
|||||||
@@ -82,16 +82,31 @@ bool us_frame_compare(const us_frame_s *a, const us_frame_s *b) {
|
|||||||
uint us_frame_get_padding(const us_frame_s *frame) {
|
uint us_frame_get_padding(const us_frame_s *frame) {
|
||||||
uint bytes_per_pixel = 0;
|
uint bytes_per_pixel = 0;
|
||||||
switch (frame->format) {
|
switch (frame->format) {
|
||||||
|
case V4L2_PIX_FMT_YUV420:
|
||||||
|
case V4L2_PIX_FMT_YVU420:
|
||||||
|
bytes_per_pixel = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case V4L2_PIX_FMT_YUYV:
|
case V4L2_PIX_FMT_YUYV:
|
||||||
case V4L2_PIX_FMT_YVYU:
|
case V4L2_PIX_FMT_YVYU:
|
||||||
case V4L2_PIX_FMT_UYVY:
|
case V4L2_PIX_FMT_UYVY:
|
||||||
case V4L2_PIX_FMT_RGB565: bytes_per_pixel = 2; break;
|
case V4L2_PIX_FMT_RGB565:
|
||||||
|
bytes_per_pixel = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
case V4L2_PIX_FMT_BGR24:
|
case V4L2_PIX_FMT_BGR24:
|
||||||
case V4L2_PIX_FMT_RGB24: bytes_per_pixel = 3; break;
|
case V4L2_PIX_FMT_RGB24:
|
||||||
|
bytes_per_pixel = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
// case V4L2_PIX_FMT_H264:
|
// case V4L2_PIX_FMT_H264:
|
||||||
case V4L2_PIX_FMT_MJPEG:
|
case V4L2_PIX_FMT_MJPEG:
|
||||||
case V4L2_PIX_FMT_JPEG: bytes_per_pixel = 0; break;
|
case V4L2_PIX_FMT_JPEG:
|
||||||
default: assert(0 && "Unknown format");
|
bytes_per_pixel = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "Unknown format");
|
||||||
}
|
}
|
||||||
if (bytes_per_pixel > 0 && frame->stride > frame->width) {
|
if (bytes_per_pixel > 0 && frame->stride > frame->width) {
|
||||||
return (frame->stride - frame->width * bytes_per_pixel);
|
return (frame->stride - frame->width * bytes_per_pixel);
|
||||||
|
|||||||
@@ -25,14 +25,8 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
#if defined(__linux__)
|
|
||||||
# define HAS_PDEATHSIG
|
|
||||||
#elif defined(__FreeBSD__)
|
|
||||||
# include <sys/param.h>
|
# include <sys/param.h>
|
||||||
# if __FreeBSD_version >= 1102000
|
|
||||||
# define HAS_PDEATHSIG
|
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -49,20 +43,22 @@
|
|||||||
# error setproctitle() not implemented, you can disable it using WITH_SETPROCTITLE=0
|
# error setproctitle() not implemented, you can disable it using WITH_SETPROCTITLE=0
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_PDEATHSIG
|
|
||||||
|
#ifdef WITH_PDEATHSIG
|
||||||
# if defined(__linux__)
|
# if defined(__linux__)
|
||||||
# include <sys/prctl.h>
|
# include <sys/prctl.h>
|
||||||
# elif defined(__FreeBSD__)
|
# elif defined(__FreeBSD__) && (__FreeBSD_version >= 1102000)
|
||||||
# include <sys/procctl.h>
|
# include <sys/procctl.h>
|
||||||
|
# else
|
||||||
|
# error WITH_PDEATHSIG is not supported on your system
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#ifdef WITH_SETPROCTITLE
|
#ifdef WITH_SETPROCTITLE
|
||||||
# include "tools.h"
|
# include "tools.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_PDEATHSIG
|
#include "logging.h"
|
||||||
# include "logging.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WITH_SETPROCTITLE
|
#ifdef WITH_SETPROCTITLE
|
||||||
@@ -70,7 +66,7 @@ extern char **environ;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAS_PDEATHSIG
|
#ifdef WITH_PDEATHSIG
|
||||||
INLINE int us_process_track_parent_death(void) {
|
INLINE int us_process_track_parent_death(void) {
|
||||||
const pid_t parent = getppid();
|
const pid_t parent = getppid();
|
||||||
int signum = SIGTERM;
|
int signum = SIGTERM;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ typedef struct {
|
|||||||
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame);
|
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame);
|
||||||
|
|
||||||
static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
||||||
|
static void _jpeg_write_scanlines_yuv_planar(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
||||||
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
||||||
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
|
||||||
#ifndef JCS_EXTENSIONS
|
#ifndef JCS_EXTENSIONS
|
||||||
@@ -50,7 +51,7 @@ static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg);
|
|||||||
static void _jpeg_term_destination(j_compress_ptr jpeg);
|
static void _jpeg_term_destination(j_compress_ptr jpeg);
|
||||||
|
|
||||||
|
|
||||||
void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned quality) {
|
void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, uint quality) {
|
||||||
// This function based on compress_image_to_jpeg() from mjpg-streamer
|
// This function based on compress_image_to_jpeg() from mjpg-streamer
|
||||||
|
|
||||||
us_frame_encoding_begin(src, dest, V4L2_PIX_FMT_JPEG);
|
us_frame_encoding_begin(src, dest, V4L2_PIX_FMT_JPEG);
|
||||||
@@ -69,11 +70,19 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
|
|||||||
switch (src->format) {
|
switch (src->format) {
|
||||||
case V4L2_PIX_FMT_YUYV:
|
case V4L2_PIX_FMT_YUYV:
|
||||||
case V4L2_PIX_FMT_YVYU:
|
case V4L2_PIX_FMT_YVYU:
|
||||||
case V4L2_PIX_FMT_UYVY: jpeg.in_color_space = JCS_YCbCr; break;
|
case V4L2_PIX_FMT_UYVY:
|
||||||
|
case V4L2_PIX_FMT_YUV420:
|
||||||
|
case V4L2_PIX_FMT_YVU420:
|
||||||
|
jpeg.in_color_space = JCS_YCbCr;
|
||||||
|
break;
|
||||||
# ifdef JCS_EXTENSIONS
|
# ifdef JCS_EXTENSIONS
|
||||||
case V4L2_PIX_FMT_BGR24: jpeg.in_color_space = JCS_EXT_BGR; break;
|
case V4L2_PIX_FMT_BGR24:
|
||||||
|
jpeg.in_color_space = JCS_EXT_BGR;
|
||||||
|
break;
|
||||||
# endif
|
# endif
|
||||||
default: jpeg.in_color_space = JCS_RGB; break;
|
default:
|
||||||
|
jpeg.in_color_space = JCS_RGB;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_set_defaults(&jpeg);
|
jpeg_set_defaults(&jpeg);
|
||||||
@@ -85,9 +94,23 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
|
|||||||
// https://www.fourcc.org/yuv.php
|
// https://www.fourcc.org/yuv.php
|
||||||
case V4L2_PIX_FMT_YUYV:
|
case V4L2_PIX_FMT_YUYV:
|
||||||
case V4L2_PIX_FMT_YVYU:
|
case V4L2_PIX_FMT_YVYU:
|
||||||
case V4L2_PIX_FMT_UYVY: _jpeg_write_scanlines_yuv(&jpeg, src); break;
|
case V4L2_PIX_FMT_UYVY:
|
||||||
case V4L2_PIX_FMT_RGB565: _jpeg_write_scanlines_rgb565(&jpeg, src); break;
|
_jpeg_write_scanlines_yuv(&jpeg, src);
|
||||||
case V4L2_PIX_FMT_RGB24: _jpeg_write_scanlines_rgb24(&jpeg, src); break;
|
break;
|
||||||
|
|
||||||
|
case V4L2_PIX_FMT_YUV420:
|
||||||
|
case V4L2_PIX_FMT_YVU420:
|
||||||
|
_jpeg_write_scanlines_yuv_planar(&jpeg, src);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case V4L2_PIX_FMT_RGB565:
|
||||||
|
_jpeg_write_scanlines_rgb565(&jpeg, src);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case V4L2_PIX_FMT_RGB24:
|
||||||
|
_jpeg_write_scanlines_rgb24(&jpeg, src);
|
||||||
|
break;
|
||||||
|
|
||||||
case V4L2_PIX_FMT_BGR24:
|
case V4L2_PIX_FMT_BGR24:
|
||||||
# ifdef JCS_EXTENSIONS
|
# ifdef JCS_EXTENSIONS
|
||||||
_jpeg_write_scanlines_rgb24(&jpeg, src); // Use native JCS_EXT_BGR
|
_jpeg_write_scanlines_rgb24(&jpeg, src); // Use native JCS_EXT_BGR
|
||||||
@@ -121,19 +144,19 @@ static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
||||||
uint8_t *line_buf;
|
u8 *line_buf;
|
||||||
US_CALLOC(line_buf, frame->width * 3);
|
US_CALLOC(line_buf, frame->width * 3);
|
||||||
|
|
||||||
const unsigned padding = us_frame_get_padding(frame);
|
const uint padding = us_frame_get_padding(frame);
|
||||||
const uint8_t *data = frame->data;
|
const u8 *data = frame->data;
|
||||||
|
|
||||||
while (jpeg->next_scanline < frame->height) {
|
while (jpeg->next_scanline < frame->height) {
|
||||||
uint8_t *ptr = line_buf;
|
u8 *ptr = line_buf;
|
||||||
|
|
||||||
for (unsigned x = 0; x < frame->width; ++x) {
|
for (uint x = 0; x < frame->width; ++x) {
|
||||||
// See also: https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-uyvy.html
|
// See also: https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-uyvy.html
|
||||||
const bool is_odd_pixel = x & 1;
|
const bool is_odd_pixel = x & 1;
|
||||||
uint8_t y, u, v;
|
u8 y, u, v;
|
||||||
if (frame->format == V4L2_PIX_FMT_YUYV) {
|
if (frame->format == V4L2_PIX_FMT_YUYV) {
|
||||||
y = data[is_odd_pixel ? 2 : 0];
|
y = data[is_odd_pixel ? 2 : 0];
|
||||||
u = data[1];
|
u = data[1];
|
||||||
@@ -167,21 +190,80 @@ static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const u
|
|||||||
free(line_buf);
|
free(line_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
static void _jpeg_write_scanlines_yuv_planar(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
||||||
uint8_t *line_buf;
|
u8 *line_buf;
|
||||||
US_CALLOC(line_buf, frame->width * 3);
|
US_CALLOC(line_buf, frame->width * 3);
|
||||||
|
|
||||||
const unsigned padding = us_frame_get_padding(frame);
|
const uint padding = us_frame_get_padding(frame);
|
||||||
const uint8_t *data = frame->data;
|
const uint image_size = frame->width * frame->height;
|
||||||
|
const uint chroma_array_size = (frame->used - image_size) / 2;
|
||||||
|
const uint chroma_matrix_order = (image_size / chroma_array_size) == 16 ? 4 : 2;
|
||||||
|
const u8 *data = frame->data;
|
||||||
|
const u8 *chroma1_data = frame->data + image_size;
|
||||||
|
const u8 *chroma2_data = frame->data + image_size + chroma_array_size;
|
||||||
|
|
||||||
|
//US_LOG_DEBUG("Planar data: Image Size %u, Chroma Array Size %u, Chroma Matrix Order %u",
|
||||||
|
// image_size, chroma_array_size, chroma_matrix_order);
|
||||||
|
|
||||||
while (jpeg->next_scanline < frame->height) {
|
while (jpeg->next_scanline < frame->height) {
|
||||||
uint8_t *ptr = line_buf;
|
u8 *ptr = line_buf;
|
||||||
|
|
||||||
for (unsigned x = 0; x < frame->width; ++x) {
|
for (uint x = 0; x < frame->width; ++x) {
|
||||||
const unsigned int two_byte = (data[1] << 8) + data[0];
|
// See also: https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuv420.html
|
||||||
|
u8 y = data[x];
|
||||||
|
u8 u;
|
||||||
|
u8 v;
|
||||||
|
uint chroma_position = x / chroma_matrix_order;
|
||||||
|
|
||||||
|
switch (frame->format) {
|
||||||
|
case V4L2_PIX_FMT_YUV420:
|
||||||
|
u = chroma1_data[chroma_position];
|
||||||
|
v = chroma2_data[chroma_position];
|
||||||
|
break;
|
||||||
|
case V4L2_PIX_FMT_YVU420:
|
||||||
|
u = chroma2_data[chroma_position];
|
||||||
|
v = chroma1_data[chroma_position];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "Unsupported pixel format");
|
||||||
|
return; // Makes linter happy
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr[0] = y;
|
||||||
|
ptr[1] = u;
|
||||||
|
ptr[2] = v;
|
||||||
|
ptr += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += frame->width + padding;
|
||||||
|
|
||||||
|
if (jpeg->next_scanline > 0 && jpeg->next_scanline % chroma_matrix_order == 0) {
|
||||||
|
chroma1_data += (frame->width + padding) / chroma_matrix_order;
|
||||||
|
chroma2_data += (frame->width + padding) / chroma_matrix_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSAMPROW scanlines[1] = {line_buf};
|
||||||
|
jpeg_write_scanlines(jpeg, scanlines, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
||||||
|
u8 *line_buf;
|
||||||
|
US_CALLOC(line_buf, frame->width * 3);
|
||||||
|
|
||||||
|
const uint padding = us_frame_get_padding(frame);
|
||||||
|
const u8 *data = frame->data;
|
||||||
|
|
||||||
|
while (jpeg->next_scanline < frame->height) {
|
||||||
|
u8 *ptr = line_buf;
|
||||||
|
|
||||||
|
for (uint x = 0; x < frame->width; ++x) {
|
||||||
|
const uint two_byte = (data[1] << 8) + data[0];
|
||||||
|
|
||||||
ptr[0] = data[1] & 248; // Red
|
ptr[0] = data[1] & 248; // Red
|
||||||
ptr[1] = (uint8_t)((two_byte & 2016) >> 3); // Green
|
ptr[1] = (u8)((two_byte & 2016) >> 3); // Green
|
||||||
ptr[2] = (data[0] & 31) * 8; // Blue
|
ptr[2] = (data[0] & 31) * 8; // Blue
|
||||||
ptr += 3;
|
ptr += 3;
|
||||||
|
|
||||||
@@ -197,8 +279,8 @@ static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
||||||
const unsigned padding = us_frame_get_padding(frame);
|
const uint padding = us_frame_get_padding(frame);
|
||||||
uint8_t *data = frame->data;
|
u8 *data = frame->data;
|
||||||
|
|
||||||
while (jpeg->next_scanline < frame->height) {
|
while (jpeg->next_scanline < frame->height) {
|
||||||
JSAMPROW scanlines[1] = {data};
|
JSAMPROW scanlines[1] = {data};
|
||||||
@@ -210,17 +292,17 @@ static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const
|
|||||||
|
|
||||||
#ifndef JCS_EXTENSIONS
|
#ifndef JCS_EXTENSIONS
|
||||||
static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
|
||||||
uint8_t *line_buf;
|
u8 *line_buf;
|
||||||
US_CALLOC(line_buf, frame->width * 3);
|
US_CALLOC(line_buf, frame->width * 3);
|
||||||
|
|
||||||
const unsigned padding = us_frame_get_padding(frame);
|
const uint padding = us_frame_get_padding(frame);
|
||||||
uint8_t *data = frame->data;
|
u8 *data = frame->data;
|
||||||
|
|
||||||
while (jpeg->next_scanline < frame->height) {
|
while (jpeg->next_scanline < frame->height) {
|
||||||
uint8_t *ptr = line_buf;
|
u8 *ptr = line_buf;
|
||||||
|
|
||||||
// swap B and R values
|
// swap B and R values
|
||||||
for (unsigned x = 0; x < frame->width * 3; x += 3) {
|
for (uint x = 0; x < frame->width * 3; x += 3) {
|
||||||
ptr[0] = data[x + 2];
|
ptr[0] = data[x + 2];
|
||||||
ptr[1] = data[x + 1];
|
ptr[1] = data[x + 1];
|
||||||
ptr[2] = data[x];
|
ptr[2] = data[x];
|
||||||
|
|||||||
@@ -35,4 +35,4 @@
|
|||||||
#include "../../../libs/frame.h"
|
#include "../../../libs/frame.h"
|
||||||
|
|
||||||
|
|
||||||
void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned quality);
|
void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, uint quality);
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ enum _US_OPT_VALUES {
|
|||||||
_O_GPIO_HAS_HTTP_CLIENTS,
|
_O_GPIO_HAS_HTTP_CLIENTS,
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef HAS_PDEATHSIG
|
# ifdef WITH_PDEATHSIG
|
||||||
_O_EXIT_ON_PARENT_DEATH,
|
_O_EXIT_ON_PARENT_DEATH,
|
||||||
# endif
|
# endif
|
||||||
_O_EXIT_ON_NO_CLIENTS,
|
_O_EXIT_ON_NO_CLIENTS,
|
||||||
@@ -224,7 +224,7 @@ static const struct option _LONG_OPTS[] = {
|
|||||||
{"gpio-has-http-clients", required_argument, NULL, _O_GPIO_HAS_HTTP_CLIENTS},
|
{"gpio-has-http-clients", required_argument, NULL, _O_GPIO_HAS_HTTP_CLIENTS},
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef HAS_PDEATHSIG
|
# ifdef WITH_PDEATHSIG
|
||||||
{"exit-on-parent-death", no_argument, NULL, _O_EXIT_ON_PARENT_DEATH},
|
{"exit-on-parent-death", no_argument, NULL, _O_EXIT_ON_PARENT_DEATH},
|
||||||
# endif
|
# endif
|
||||||
{"exit-on-no-clients", required_argument, NULL, _O_EXIT_ON_NO_CLIENTS},
|
{"exit-on-no-clients", required_argument, NULL, _O_EXIT_ON_NO_CLIENTS},
|
||||||
@@ -483,7 +483,7 @@ int options_parse(us_options_s *options, us_capture_s *cap, us_encoder_s *enc, u
|
|||||||
case _O_GPIO_HAS_HTTP_CLIENTS: OPT_NUMBER("--gpio-has-http-clients", us_g_gpio.has_http_clients.pin, 0, 256, 0);
|
case _O_GPIO_HAS_HTTP_CLIENTS: OPT_NUMBER("--gpio-has-http-clients", us_g_gpio.has_http_clients.pin, 0, 256, 0);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef HAS_PDEATHSIG
|
# ifdef WITH_PDEATHSIG
|
||||||
case _O_EXIT_ON_PARENT_DEATH:
|
case _O_EXIT_ON_PARENT_DEATH:
|
||||||
if (us_process_track_parent_death() < 0) {
|
if (us_process_track_parent_death() < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -581,34 +581,52 @@ static int _check_instance_id(const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _features(void) {
|
static void _features(void) {
|
||||||
# ifdef WITH_GPIO
|
# ifdef MK_WITH_PYTHON
|
||||||
|
puts("+ WITH_PYTHON");
|
||||||
|
# else
|
||||||
|
puts("- WITH_PYTHON");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef MK_WITH_JANUS
|
||||||
|
puts("+ WITH_JANUS");
|
||||||
|
# else
|
||||||
|
puts("- WITH_JANUS");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef MK_WITH_V4P
|
||||||
|
puts("+ WITH_V4P");
|
||||||
|
# else
|
||||||
|
puts("- WITH_V4P");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef MK_WITH_GPIO
|
||||||
puts("+ WITH_GPIO");
|
puts("+ WITH_GPIO");
|
||||||
# else
|
# else
|
||||||
puts("- WITH_GPIO");
|
puts("- WITH_GPIO");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_SYSTEMD
|
# ifdef MK_WITH_SYSTEMD
|
||||||
puts("+ WITH_SYSTEMD");
|
puts("+ WITH_SYSTEMD");
|
||||||
# else
|
# else
|
||||||
puts("- WITH_SYSTEMD");
|
puts("- WITH_SYSTEMD");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_PTHREAD_NP
|
# ifdef MK_WITH_PTHREAD_NP
|
||||||
puts("+ WITH_PTHREAD_NP");
|
puts("+ WITH_PTHREAD_NP");
|
||||||
# else
|
# else
|
||||||
puts("- WITH_PTHREAD_NP");
|
puts("- WITH_PTHREAD_NP");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_SETPROCTITLE
|
# ifdef MK_WITH_SETPROCTITLE
|
||||||
puts("+ WITH_SETPROCTITLE");
|
puts("+ WITH_SETPROCTITLE");
|
||||||
# else
|
# else
|
||||||
puts("- WITH_SETPROCTITLE");
|
puts("- WITH_SETPROCTITLE");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef HAS_PDEATHSIG
|
# ifdef MK_WITH_PDEATHSIG
|
||||||
puts("+ HAS_PDEATHSIG");
|
puts("+ WITH_PDEATHSIG");
|
||||||
# else
|
# else
|
||||||
puts("- HAS_PDEATHSIG");
|
puts("- WITH_PDEATHSIG");
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,11 +758,11 @@ static void _help(FILE *fp, const us_capture_s *cap, const us_encoder_s *enc, co
|
|||||||
SAY(" --gpio-stream-online <pin> ──── Set 1 while streaming. Default: disabled.\n");
|
SAY(" --gpio-stream-online <pin> ──── Set 1 while streaming. Default: disabled.\n");
|
||||||
SAY(" --gpio-has-http-clients <pin> ─ Set 1 while stream has at least one client. Default: disabled.\n");
|
SAY(" --gpio-has-http-clients <pin> ─ Set 1 while stream has at least one client. Default: disabled.\n");
|
||||||
# endif
|
# endif
|
||||||
# if (defined(HAS_PDEATHSIG) || defined(WITH_SETPROCTITLE))
|
# if (defined(WITH_PDEATHSIG) || defined(WITH_SETPROCTITLE))
|
||||||
SAY("Process options:");
|
SAY("Process options:");
|
||||||
SAY("════════════════");
|
SAY("════════════════");
|
||||||
# endif
|
# endif
|
||||||
# ifdef HAS_PDEATHSIG
|
# ifdef WITH_PDEATHSIG
|
||||||
SAY(" --exit-on-parent-death ─────── Exit the program if the parent process is dead. Default: disabled.\n");
|
SAY(" --exit-on-parent-death ─────── Exit the program if the parent process is dead. Default: disabled.\n");
|
||||||
# endif
|
# endif
|
||||||
SAY(" --exit-on-no-clients <sec> ──── Exit the program if there have been no stream or sink clients");
|
SAY(" --exit-on-no-clients <sec> ──── Exit the program if there have been no stream or sink clients");
|
||||||
|
|||||||
Reference in New Issue
Block a user