Compare commits

...

23 Commits
v6.4 ... v6.8

Author SHA1 Message Date
Maxim Devaev
d43014346d Bump version: 6.7 → 6.8 2024-03-26 20:23:16 +02:00
Maxim Devaev
bcd447963c build fix 2024-03-26 20:22:10 +02:00
Maxim Devaev
eec6cfd0d4 lint fix 2024-03-26 20:10:06 +02:00
Maxim Devaev
f177300e69 ustreamer/drm: fixed assertion 2024-03-26 18:59:33 +02:00
Maxim Devaev
7015a26a63 Userspace workaround for the wrong TC358743 RGB bytes ordering
- https://github.com/raspberrypi/linux/issues/6068
2024-03-26 18:35:13 +02:00
Maxim Devaev
290282b6b6 drm: fixed big endian case for rgb/bgr 2024-03-26 18:05:51 +02:00
Maxim Devaev
a339ff5d06 v4p mode in ustreamer 2024-03-26 17:45:53 +02:00
Maxim Devaev
8d4e9a6ca0 renamed us_hw_buffer_s to us_capture_hwbuf_s 2024-03-26 01:54:01 +02:00
Maxim Devaev
f0f5fcd67f renamed us_device* to us_capture* 2024-03-26 01:25:04 +02:00
Maxim Devaev
02fabc7b45 Bump version: 6.6 → 6.7 2024-03-25 20:16:52 +02:00
Maxim Devaev
bdf55396e5 fixed memsink data offset 2024-03-25 20:15:38 +02:00
Maxim Devaev
976f466038 PKGBUILD: fixed missing python-wheel 2024-03-23 19:40:29 +02:00
Maxim Devaev
b79b4fd55e Bump version: 6.5 → 6.6 2024-03-22 15:58:21 +02:00
Maxim Devaev
6d77f5334f updated copyright date 2024-03-22 15:57:16 +02:00
Maxim Devaev
25957de017 direct call of setup.py is deprecated 2024-03-22 15:55:06 +02:00
Maxim Devaev
847f34e10c fixed symlink 2024-03-22 14:12:43 +02:00
Maxim Devaev
0ab8e0d05e DESTDIR always transformed to absolute R_DESTDIR 2024-03-22 12:59:37 +02:00
Kiyofumi Kondoh
ac88996a8c adapt pacman 6.1 and lower version (#266)
* adapt pacman 6.1 and lower version

* remove legacy operation
2024-03-21 22:47:23 +02:00
Maxim Devaev
408157c82b Bump version: 6.4 → 6.5 2024-03-21 13:33:29 +02:00
Maxim Devaev
7356dea737 renamed options --sink* to --jpeg-sink* 2024-03-21 13:21:51 +02:00
Maxim Devaev
87a75a816a memsink: suffix-based memory limites 2024-03-20 22:55:37 +02:00
Maxim Devaev
b6a2332207 refactoring 2024-03-20 17:51:56 +02:00
Maxim Devaev
34c0dcb1ce refactoring 2024-03-19 19:33:55 +02:00
122 changed files with 915 additions and 710 deletions

View File

@@ -1,7 +1,7 @@
[bumpversion]
commit = True
tag = True
current_version = 6.4
current_version = 6.8
parse = (?P<major>\d+)\.(?P<minor>\d+)
serialize =
{major}.{minor}

3
.gitignore vendored
View File

@@ -3,8 +3,9 @@
/pkg/arch/pkg/
/pkg/arch/src/
/src/build/
/python/build/
/python/dist/
/python/ustreamer.egg-info/
/python/root/
/janus/build/
/ustreamer
/ustreamer-*

View File

@@ -9,6 +9,8 @@ PY ?= python3
CFLAGS ?= -O3
LDFLAGS ?=
R_DESTDIR = $(if $(DESTDIR),$(shell realpath "$(DESTDIR)"),)
export
_LINTERS_IMAGE ?= ustreamer-linters
@@ -43,7 +45,7 @@ apps:
python:
$(MAKE) -C python
$(ECHO) ln -sf python/build/lib.*/*.so .
$(ECHO) ln -sf python/root/usr/lib/python*/site-packages/*.so .
janus:
@@ -59,10 +61,10 @@ endif
ifneq ($(call optbool,$(WITH_JANUS)),)
$(MAKE) -C janus install
endif
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
mkdir -p $(R_DESTDIR)$(MANPREFIX)/man1
for man in $(shell ls man); do \
install -m644 man/$$man $(DESTDIR)$(MANPREFIX)/man1/$$man; \
gzip -f $(DESTDIR)$(MANPREFIX)/man1/$$man; \
install -m644 man/$$man $(R_DESTDIR)$(MANPREFIX)/man1/$$man; \
gzip -f $(R_DESTDIR)$(MANPREFIX)/man1/$$man; \
done

View File

@@ -209,7 +209,7 @@ v4l2 utilities provide the tools to manage USB webcam setting and information. S
-----
# License
Copyright (C) 2018-2023 by Maxim Devaev mdevaev@gmail.com
Copyright (C) 2018-2024 by 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

View File

@@ -1,4 +1,4 @@
DESTDIR ?=
R_DESTDIR ?=
PREFIX ?= /usr/local
CC ?= gcc
@@ -42,8 +42,8 @@ $(_BUILD)/%.o: %.c
install: $(_PLUGIN)
mkdir -p $(DESTDIR)$(PREFIX)/lib/ustreamer/janus
install -m755 $(_PLUGIN) $(DESTDIR)$(PREFIX)/lib/ustreamer/janus/$(PLUGIN)
mkdir -p $(R_DESTDIR)$(PREFIX)/lib/ustreamer/janus
install -m755 $(_PLUGIN) $(R_DESTDIR)$(PREFIX)/lib/ustreamer/janus/$(PLUGIN)
clean:

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -214,7 +214,7 @@ static _enc_buffer_s *_enc_buffer_init(void) {
static void *_pcm_thread(void *v_audio) {
US_THREAD_SETTLE("us_a_pcm");
us_audio_s *const audio = (us_audio_s *)v_audio;
us_audio_s *const audio = v_audio;
u8 in[_MAX_BUF8];
while (!atomic_load(&audio->stop)) {
@@ -244,7 +244,7 @@ static void *_pcm_thread(void *v_audio) {
static void *_encoder_thread(void *v_audio) {
US_THREAD_SETTLE("us_a_enc");
us_audio_s *const audio = (us_audio_s *)v_audio;
us_audio_s *const audio = v_audio;
s16 in_res[_MAX_BUF16];
while (!atomic_load(&audio->stop)) {

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -104,7 +104,7 @@ static void *_audio_thread(void *v_client) {
}
static void *_common_thread(void *v_client, bool video) {
us_janus_client_s *const client = (us_janus_client_s *)v_client;
us_janus_client_s *const client = v_client;
us_ring_s *const ring = (video ? client->video_ring : client->audio_ring);
assert(ring != NULL); // Audio may be NULL

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -58,7 +58,7 @@ int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s *mem, u64 last_id) {
}
int us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, us_frame_s *frame, u64 *frame_id, bool key_required) {
us_frame_set_data(frame, mem->data, mem->used);
us_frame_set_data(frame, us_memsink_get_data(mem), mem->used);
US_FRAME_COPY_META(mem, frame);
*frame_id = mem->id;
mem->last_client_ts = us_get_now_monotonic();

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -136,12 +136,18 @@ static void *_video_sink_thread(void *arg) {
int fd = -1;
us_memsink_shared_s *mem = NULL;
const uz data_size = us_memsink_calculate_size(_g_config->video_sink_name);
if (data_size == 0) {
US_ONCE({ US_JLOG_ERROR("video", "Invalid memsink object suffix"); });
goto close_memsink;
}
if ((fd = shm_open(_g_config->video_sink_name, O_RDWR, 0)) <= 0) {
US_ONCE({ US_JLOG_PERROR("video", "Can't open memsink"); });
goto close_memsink;
}
if ((mem = us_memsink_shared_map(fd)) == NULL) {
if ((mem = us_memsink_shared_map(fd, data_size)) == NULL) {
US_ONCE({ US_JLOG_PERROR("video", "Can't map memsink"); });
goto close_memsink;
}
@@ -178,7 +184,10 @@ static void *_video_sink_thread(void *arg) {
}
close_memsink:
US_DELETE(mem, us_memsink_shared_unmap);
if (mem != NULL) {
us_memsink_shared_unmap(mem, data_size);
mem = NULL;
}
US_CLOSE_FD(fd);
US_JLOG_INFO("video", "Memsink closed");
sleep(1); // error_delay

View File

@@ -5,7 +5,7 @@
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -57,7 +57,7 @@ void us_rtp_write_header(us_rtp_s *rtp, u32 pts, bool marked) {
++rtp->seq;
# define WRITE_BE_U32(x_offset, x_value) \
*((u32 *)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value)
*((u32*)(rtp->datagram + x_offset)) = __builtin_bswap32(x_value)
WRITE_BE_U32(0, word0);
WRITE_BE_U32(4, pts);
WRITE_BE_U32(8, rtp->ssrc);

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -5,7 +5,7 @@
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -0,0 +1 @@
../../../src/libs/memsinksh.c

View File

@@ -1,44 +0,0 @@
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 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 <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef long long sll;
typedef ssize_t sz;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef unsigned uint;
typedef unsigned long long ull;
typedef size_t uz;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef long double ldf;

1
janus/src/uslibs/types.h Symbolic link
View File

@@ -0,0 +1 @@
../../../src/libs/types.h

View File

@@ -1,6 +1,6 @@
.\" Manpage for ustreamer-dump.
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
.TH USTREAMER-DUMP 1 "version 6.4" "January 2021"
.TH USTREAMER-DUMP 1 "version 6.8" "January 2021"
.SH NAME
ustreamer-dump \- Dump uStreamer's memory sink to file

View File

@@ -1,6 +1,6 @@
.\" Manpage for ustreamer.
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
.TH USTREAMER 1 "version 6.4" "November 2020"
.TH USTREAMER 1 "version 6.8" "November 2020"
.SH NAME
ustreamer \- stream MJPEG video from any V4L2 device to the network
@@ -212,25 +212,25 @@ Timeout for client connections. Default: 10.
.SS "JPEG sink options"
With shared memory sink you can write a stream to a file. See \fBustreamer-dump\fR(1) for more info.
.TP
.BR \-\-sink\ \fIname
Use the specified shared memory object to sink JPEG frames. Default: disabled.
.BR \-\-jpeg\-sink\ \fIname
Use the specified shared memory object to sink JPEG frames. The name should end with a suffix ".jpeg" or ":jpeg". Default: disabled.
.TP
.BR \-\-sink\-mode\ \fImode
.BR \-\-jpeg\-sink\-mode\ \fImode
Set JPEG sink permissions (like 777). Default: 660.
.TP
.BR \-\-sink\-rm
.BR \-\-jpeg\-sink\-rm
Remove shared memory on stop. Default: disabled.
.TP
.BR \-\-sink\-client\-ttl\ \fIsec
.BR \-\-jpeg\-sink\-client\-ttl\ \fIsec
Client TTL. Default: 10.
.TP
.BR \-\-sink\-timeout\ \fIsec
.BR \-\-jpeg\-sink\-timeout\ \fIsec
Timeout for lock. Default: 1.
.SS "H264 sink options"
.TP
.BR \-\-h264\-sink\ \fIname
Use the specified shared memory object to sink H264 frames. Default: disabled.
Use the specified shared memory object to sink H264 frames. The name should end with a suffix ".h264" or ":h264". Default: disabled.
.TP
.BR \-\-h264\-sink\-mode\ \fImode
Set H264 sink permissions (like 777). Default: 660.
@@ -253,6 +253,22 @@ Interval between keyframes. Default: 30.
.BR \-\-h264\-m2m\-device\ \fI/dev/path
Path to V4L2 mem-to-mem encoder device. Default: auto-select.
.SS "RAW sink options"
.TP
.BR \-\-raw\-sink\ \fIname
Use the specified shared memory object to sink RAW frames. The name should end with a suffix ".raw" or ":raw". Default: disabled.
.TP
.BR \-\-raw\-sink\-mode\ \fImode
Set RAW sink permissions (like 777). Default: 660.
.TP
.BR \-\-raw\-sink\-rm
Remove shared memory on stop. Default: disabled.
.TP
.BR \-\-raw\-sink\-client\-ttl\ \fIsec
Client TTL. Default: 10.
.TP
.BR \-\-raw\-sink\-timeout\ \fIsec
Timeout for lock. Default: 1.
.SS "Process options"
.TP

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer
pkgver=6.4
pkgver=6.8
pkgrel=1
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
url="https://github.com/pikvm/ustreamer"
@@ -19,7 +19,7 @@ _options="WITH_GPIO=1 WITH_SYSTEMD=1"
if [ -e /usr/bin/python3 ]; then
_options="$_options WITH_PYTHON=1"
depends+=(python)
makedepends+=(python-setuptools)
makedepends+=(python-setuptools python-pip python-build python-wheel)
fi
if [ -e /usr/include/janus/plugins/plugin.h ];then
depends+=(janus-gateway alsa-lib opus)
@@ -28,12 +28,6 @@ if [ -e /usr/include/janus/plugins/plugin.h ];then
fi
# LD does not link mmal with this option
# This DOESN'T affect setup.py
LDFLAGS="${LDFLAGS//--as-needed/}"
export LDFLAGS="${LDFLAGS//,,/,}"
build() {
cd "$srcdir"
rm -rf $pkgname-build

View File

@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=ustreamer
PKG_VERSION:=6.4
PKG_VERSION:=6.8
PKG_RELEASE:=1
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>

2
python/MANIFEST.in Normal file
View File

@@ -0,0 +1,2 @@
include setup.py
recursive-include src *.c *h

View File

@@ -1,6 +1,6 @@
-include ../config.mk
DESTDIR ?=
R_DESTDIR ?=
PREFIX ?= /usr/local
PY ?= python3
@@ -9,12 +9,14 @@ PY ?= python3
# =====
all:
$(info == PY_BUILD ustreamer-*.so)
$(ECHO) $(PY) setup.py build
rm -rf root
$(ECHO) $(PY) -m build --skip-dependency-check --no-isolation
$(ECHO) $(PY) -m pip install dist/*.whl --ignore-installed --root=./root
install:
$(PY) setup.py install --prefix=$(PREFIX) --root=$(if $(DESTDIR),$(DESTDIR),/)
$(PY) -m pip install dist/*.whl --ignore-installed --prefix=$(PREFIX) --root=$(if $(R_DESTDIR),$(R_DESTDIR),/)
clean:
rm -rf build ustreamer.egg-info
rm -rf root dist ustreamer.egg-info

View File

@@ -17,7 +17,7 @@ def _find_sources(suffix: str) -> list[str]:
if __name__ == "__main__":
setup(
name="ustreamer",
version="6.4",
version="6.8",
description="uStreamer tools",
author="Maxim Devaev",
author_email="mdevaev@gmail.com",
@@ -29,7 +29,6 @@ if __name__ == "__main__":
extra_compile_args=["-std=c17", "-D_GNU_SOURCE"],
undef_macros=["NDEBUG"],
sources=_find_sources(".c"),
depends=_find_sources(".h"),
),
],
)

View File

@@ -0,0 +1 @@
../../../src/libs/memsinksh.c

View File

@@ -1,44 +0,0 @@
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 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 <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef long long sll;
typedef ssize_t sz;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef unsigned uint;
typedef unsigned long long ull;
typedef size_t uz;
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef long double ldf;

1
python/src/uslibs/types.h Symbolic link
View File

@@ -0,0 +1 @@
../../../src/libs/types.h

View File

@@ -26,6 +26,7 @@ typedef struct {
double lock_timeout;
double wait_timeout;
double drop_same_frames;
uz data_size;
int fd;
us_memsink_shared_s *mem;
@@ -37,7 +38,10 @@ typedef struct {
static void _MemsinkObject_destroy_internals(_MemsinkObject *self) {
US_DELETE(self->mem, us_memsink_shared_unmap);
if (self->mem != NULL) {
us_memsink_shared_unmap(self->mem, self->data_size);
self->mem = NULL;
}
US_CLOSE_FD(self->fd);
US_DELETE(self->frame, us_frame_destroy);
}
@@ -64,13 +68,18 @@ static int _MemsinkObject_init(_MemsinkObject *self, PyObject *args, PyObject *k
SET_DOUBLE(drop_same_frames, >= 0);
# undef SET_DOUBLE
if ((self->data_size = us_memsink_calculate_size(self->obj)) == 0) {
PyErr_SetString(PyExc_ValueError, "Invalid memsink object suffix");
return -1;
}
self->frame = us_frame_init();
if ((self->fd = shm_open(self->obj, O_RDWR, 0)) == -1) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
if ((self->mem = us_memsink_shared_map(self->fd)) == NULL) {
if ((self->mem = us_memsink_shared_map(self->fd, self->data_size)) == NULL) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;
}
@@ -99,11 +108,11 @@ static PyObject *_MemsinkObject_close(_MemsinkObject *self, PyObject *Py_UNUSED(
static PyObject *_MemsinkObject_enter(_MemsinkObject *self, PyObject *Py_UNUSED(ignored)) {
Py_INCREF(self);
return (PyObject *)self;
return (PyObject*)self;
}
static PyObject *_MemsinkObject_exit(_MemsinkObject *self, PyObject *Py_UNUSED(ignored)) {
return PyObject_CallMethod((PyObject *)self, "close", "");
return PyObject_CallMethod((PyObject*)self, "close", "");
}
static int _wait_frame(_MemsinkObject *self) {
@@ -139,7 +148,7 @@ static int _wait_frame(_MemsinkObject *self) {
if (
US_FRAME_COMPARE_GEOMETRY(self->mem, self->frame)
&& (self->frame_ts + self->drop_same_frames > now_ts)
&& !memcmp(self->frame->data, mem->data, mem->used)
&& !memcmp(self->frame->data, us_memsink_get_data(mem), mem->used)
) {
self->frame_id = mem->id;
goto retry;
@@ -190,7 +199,7 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args,
}
us_memsink_shared_s *mem = self->mem;
us_frame_set_data(self->frame, mem->data, mem->used);
us_frame_set_data(self->frame, us_memsink_get_data(mem), mem->used);
US_FRAME_COPY_META(self->mem, self->frame);
self->frame_id = mem->id;
self->frame_ts = us_get_now_monotonic();
@@ -230,7 +239,7 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args,
SET_NUMBER(grab_ts, Double, Float);
SET_NUMBER(encode_begin_ts, Double, Float);
SET_NUMBER(encode_end_ts, Double, Float);
SET_VALUE("data", PyBytes_FromStringAndSize((const char *)self->frame->data, self->frame->used));
SET_VALUE("data", PyBytes_FromStringAndSize((const char*)self->frame->data, self->frame->used));
# undef SET_NUMBER
# undef SET_VALUE
@@ -305,7 +314,7 @@ PyMODINIT_FUNC PyInit_ustreamer(void) {
Py_INCREF(&_MemsinkType);
if (PyModule_AddObject(module, "Memsink", (PyObject *)&_MemsinkType) < 0) {
if (PyModule_AddObject(module, "Memsink", (PyObject*)&_MemsinkType) < 0) {
return NULL;
}

View File

@@ -1,4 +1,4 @@
DESTDIR ?=
R_DESTDIR ?=
PREFIX ?= /usr/local
CC ?= gcc
@@ -12,11 +12,11 @@ _DUMP = ustreamer-dump.bin
_V4P = ustreamer-v4p.bin
_CFLAGS = -MD -c -std=c17 -Wall -Wextra -D_GNU_SOURCE $(CFLAGS)
_LDFLAGS = $(LDFLAGS)
_COMMON_LIBS = -lm -ljpeg -pthread -lrt -latomic
_USTR_LDFLAGS = $(LDFLAGS) -lm -ljpeg -pthread -lrt -latomic -levent -levent_pthreads
_DUMP_LDFLAGS = $(LDFLAGS) -lm -ljpeg -pthread -lrt -latomic
_V4P_LDFLAGS = $(LDFLAGS) -lm -ljpeg -pthread -lrt -latomic
_USTR_LIBS = $(_COMMON_LIBS) -levent -levent_pthreads
_USTR_SRCS = $(shell ls \
libs/*.c \
ustreamer/*.c \
@@ -27,15 +27,14 @@ _USTR_SRCS = $(shell ls \
ustreamer/*.c \
)
_DUMP_LIBS = $(_COMMON_LIBS)
_DUMP_SRCS = $(shell ls \
libs/*.c \
dump/*.c \
)
_V4P_LIBS = $(_COMMON_LIBS)
_V4P_SRCS = $(shell ls \
libs/*.c \
libs/drm/*.c \
v4p/*.c \
)
@@ -52,16 +51,16 @@ endef
ifneq ($(call optbool,$(WITH_GPIO)),)
_USTR_LIBS += -lgpiod
override _CFLAGS += -DWITH_GPIO $(shell pkg-config --atleast-version=2 libgpiod 2> /dev/null && echo -DHAVE_GPIOD2)
_USTR_SRCS += $(shell ls ustreamer/gpio/*.c)
override _USTR_LDFLAGS += -lgpiod
override _USTR_SRCS += $(shell ls ustreamer/gpio/*.c)
endif
ifneq ($(call optbool,$(WITH_SYSTEMD)),)
_USTR_LIBS += -lsystemd
override _CFLAGS += -DWITH_SYSTEMD
_USTR_SRCS += $(shell ls ustreamer/http/systemd/*.c)
override _USTR_LDFLAGS += -lsystemd
override _USTR_SRCS += $(shell ls ustreamer/http/systemd/*.c)
endif
@@ -73,10 +72,10 @@ endif
WITH_SETPROCTITLE ?= 1
ifneq ($(call optbool,$(WITH_SETPROCTITLE)),)
ifeq ($(shell uname -s | tr A-Z a-z),linux)
_USTR_LIBS += -lbsd
endif
override _CFLAGS += -DWITH_SETPROCTITLE
ifeq ($(shell uname -s | tr A-Z a-z),linux)
override _USTR_LDFLAGS += -lbsd
endif
endif
@@ -84,8 +83,10 @@ WITH_V4P ?= 0
ifneq ($(call optbool,$(WITH_V4P)),)
override _TARGETS += $(_V4P)
override _OBJS += $(_V4P_SRCS:%.c=$(_BUILD)/%.o)
override _CFLAGS += $(shell pkg-config --cflags libdrm)
_V4P_LDFLAGS = $(shell pkg-config --libs libdrm)
override _CFLAGS += -DWITH_V4P $(shell pkg-config --cflags libdrm)
override _V4P_LDFLAGS += $(shell pkg-config --libs libdrm)
override _USTR_SRCS += $(shell ls libs/drm/*.c)
override _USTR_LDFLAGS += $(shell pkg-config --libs libdrm)
endif
@@ -94,29 +95,31 @@ all: $(_TARGETS)
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
mkdir -p $(R_DESTDIR)$(PREFIX)/bin
for i in $(subst .bin,,$(_TARGETS)); do \
install -m755 $$i.bin $(DESTDIR)$(PREFIX)/bin/$$i; \
install -m755 $$i.bin $(R_DESTDIR)$(PREFIX)/bin/$$i; \
done
install-strip: install
for i in $(subst .bin,,$(_TARGETS)); do strip $(DESTDIR)$(PREFIX)/bin/$$i; done
for i in $(subst .bin,,$(_TARGETS)); do \
strip $(R_DESTDIR)$(PREFIX)/bin/$$i; \
done
$(_USTR): $(_USTR_SRCS:%.c=$(_BUILD)/%.o)
$(info == LD $@)
$(ECHO) $(CC) $^ -o $@ $(_LDFLAGS) $(_USTR_LIBS)
$(ECHO) $(CC) $^ -o $@ $(_USTR_LDFLAGS)
$(_DUMP): $(_DUMP_SRCS:%.c=$(_BUILD)/%.o)
$(info == LD $@)
$(ECHO) $(CC) $^ -o $@ $(_LDFLAGS) $(_DUMP_LIBS)
$(ECHO) $(CC) $^ -o $@ $(_DUMP_LDFLAGS)
$(_V4P): $(_V4P_SRCS:%.c=$(_BUILD)/%.o)
$(info == LD $@)
$(ECHO) $(CC) $^ -o $@ $(_LDFLAGS) $(_V4P_LDFLAGS) $(_V4P_LIBS)
$(ECHO) $(CC) $^ -o $@ $(_V4P_LDFLAGS)
$(_BUILD)/%.o: %.c

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -47,7 +47,7 @@ us_output_file_s *us_output_file_init(const char *path, bool json) {
}
void us_output_file_write(void *v_output, const us_frame_s *frame) {
us_output_file_s *output = (us_output_file_s *)v_output;
us_output_file_s *output = v_output;
if (output->json) {
us_base64_encode(frame->data, frame->used, &output->base64_data, &output->base64_allocated);
fprintf(output->fp,
@@ -66,7 +66,7 @@ void us_output_file_write(void *v_output, const us_frame_s *frame) {
}
void us_output_file_destroy(void *v_output) {
us_output_file_s *output = (us_output_file_s *)v_output;
us_output_file_s *output = v_output;
US_DELETE(output->base64_data, free);
if (output->fp && output->fp != stdout) {
if (fclose(output->fp) < 0) {

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -182,7 +182,7 @@ int main(int argc, char *argv[]) {
_output_context_s ctx = {0};
if (output_path && output_path[0] != '\0') {
if ((ctx.v_output = (void *)us_output_file_init(output_path, output_json)) == NULL) {
if ((ctx.v_output = (void*)us_output_file_init(output_path, output_json)) == NULL) {
return 1;
}
ctx.write = us_output_file_write;
@@ -296,7 +296,7 @@ static void _help(FILE *fp) {
SAY("\nuStreamer-dump - Dump uStreamer's memory sink to file");
SAY("═════════════════════════════════════════════════════");
SAY("Version: %s; license: GPLv3", US_VERSION);
SAY("Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com>\n");
SAY("Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com>\n");
SAY("Example:");
SAY("════════");
SAY(" ustreamer-dump --sink test --output - \\");

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -20,7 +20,7 @@
*****************************************************************************/
#include "device.h"
#include "capture.h"
#include <stdlib.h>
#include <stdatomic.h>
@@ -81,28 +81,28 @@ static const struct {
{"USERPTR", V4L2_MEMORY_USERPTR},
};
static int _device_wait_buffer(us_device_s *dev);
static int _device_consume_event(us_device_s *dev);
static int _capture_wait_buffer(us_capture_s *cap);
static int _capture_consume_event(us_capture_s *cap);
static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer *dest);
static bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, const u8 *data);
static int _device_open_check_cap(us_device_s *dev);
static int _device_open_dv_timings(us_device_s *dev, bool apply);
static int _device_open_format(us_device_s *dev, bool first);
static void _device_open_hw_fps(us_device_s *dev);
static void _device_open_jpeg_quality(us_device_s *dev);
static int _device_open_io_method(us_device_s *dev);
static int _device_open_io_method_mmap(us_device_s *dev);
static int _device_open_io_method_userptr(us_device_s *dev);
static int _device_open_queue_buffers(us_device_s *dev);
static int _device_open_export_to_dma(us_device_s *dev);
static int _device_apply_resolution(us_device_s *dev, uint width, uint height, float hz);
static bool _capture_is_buffer_valid(us_capture_s *cap, const struct v4l2_buffer *buf, const u8 *data);
static int _capture_open_check_cap(us_capture_s *cap);
static int _capture_open_dv_timings(us_capture_s *cap, bool apply);
static int _capture_open_format(us_capture_s *cap, bool first);
static void _capture_open_hw_fps(us_capture_s *cap);
static void _capture_open_jpeg_quality(us_capture_s *cap);
static int _capture_open_io_method(us_capture_s *cap);
static int _capture_open_io_method_mmap(us_capture_s *cap);
static int _capture_open_io_method_userptr(us_capture_s *cap);
static int _capture_open_queue_buffers(us_capture_s *cap);
static int _capture_open_export_to_dma(us_capture_s *cap);
static int _capture_apply_resolution(us_capture_s *cap, uint width, uint height, float hz);
static void _device_apply_controls(us_device_s *dev);
static int _device_query_control(
us_device_s *dev, struct v4l2_queryctrl *query,
static void _capture_apply_controls(us_capture_s *cap);
static int _capture_query_control(
us_capture_s *cap, struct v4l2_queryctrl *query,
const char *name, uint cid, bool quiet);
static void _device_set_control(
us_device_s *dev, const struct v4l2_queryctrl *query,
static void _capture_set_control(
us_capture_s *cap, const struct v4l2_queryctrl *query,
const char *name, uint cid, int value, bool quiet);
static const char *_format_to_string_nullable(uint format);
@@ -118,33 +118,33 @@ static const char *_io_method_to_string_supported(enum v4l2_memory io_method);
#define _D_LOG_DEBUG(x_msg, ...) US_LOG_DEBUG("CAP: " x_msg, ##__VA_ARGS__)
us_device_s *us_device_init(void) {
us_device_runtime_s *run;
us_capture_s *us_capture_init(void) {
us_capture_runtime_s *run;
US_CALLOC(run, 1);
run->fd = -1;
us_device_s *dev;
US_CALLOC(dev, 1);
dev->path = "/dev/video0";
dev->width = 640;
dev->height = 480;
dev->format = V4L2_PIX_FMT_YUYV;
dev->jpeg_quality = 80;
dev->standard = V4L2_STD_UNKNOWN;
dev->io_method = V4L2_MEMORY_MMAP;
dev->n_bufs = us_get_cores_available() + 1;
dev->min_frame_size = 128;
dev->timeout = 1;
dev->run = run;
return dev;
us_capture_s *cap;
US_CALLOC(cap, 1);
cap->path = "/dev/video0";
cap->width = 640;
cap->height = 480;
cap->format = V4L2_PIX_FMT_YUYV;
cap->jpeg_quality = 80;
cap->standard = V4L2_STD_UNKNOWN;
cap->io_method = V4L2_MEMORY_MMAP;
cap->n_bufs = us_get_cores_available() + 1;
cap->min_frame_size = 128;
cap->timeout = 1;
cap->run = run;
return cap;
}
void us_device_destroy(us_device_s *dev) {
free(dev->run);
free(dev);
void us_capture_destroy(us_capture_s *cap) {
free(cap->run);
free(cap);
}
int us_device_parse_format(const char *str) {
int us_capture_parse_format(const char *str) {
US_ARRAY_ITERATE(_FORMATS, 0, item, {
if (!strcasecmp(item->name, str)) {
return item->format;
@@ -153,7 +153,7 @@ int us_device_parse_format(const char *str) {
return -1;
}
int us_device_parse_standard(const char *str) {
int us_capture_parse_standard(const char *str) {
US_ARRAY_ITERATE(_STANDARDS, 0, item, {
if (!strcasecmp(item->name, str)) {
return item->standard;
@@ -162,7 +162,7 @@ int us_device_parse_standard(const char *str) {
return -1;
}
int us_device_parse_io_method(const char *str) {
int us_capture_parse_io_method(const char *str) {
US_ARRAY_ITERATE(_IO_METHODS, 0, item, {
if (!strcasecmp(item->name, str)) {
return item->io_method;
@@ -171,10 +171,10 @@ int us_device_parse_io_method(const char *str) {
return -1;
}
int us_device_open(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
int us_capture_open(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
if (access(dev->path, R_OK | W_OK) < 0) {
if (access(cap->path, R_OK | W_OK) < 0) {
if (run->open_error_reported != -errno) {
run->open_error_reported = -errno; // Don't confuse it with __LINE__
US_LOG_PERROR("No access to capture device");
@@ -183,15 +183,15 @@ int us_device_open(us_device_s *dev) {
}
_D_LOG_DEBUG("Opening capture device ...");
if ((run->fd = open(dev->path, O_RDWR | O_NONBLOCK)) < 0) {
if ((run->fd = open(cap->path, O_RDWR | O_NONBLOCK)) < 0) {
_D_LOG_PERROR("Can't capture open device");
goto error;
}
_D_LOG_DEBUG("Capture device fd=%d opened", run->fd);
if (dev->dv_timings && dev->persistent) {
if (cap->dv_timings && cap->persistent) {
_D_LOG_DEBUG("Probing DV-timings or QuerySTD ...");
if (_device_open_dv_timings(dev, false) < 0) {
if (_capture_open_dv_timings(cap, false) < 0) {
const int line = __LINE__;
if (run->open_error_reported != line) {
run->open_error_reported = line;
@@ -201,34 +201,34 @@ int us_device_open(us_device_s *dev) {
}
}
if (_device_open_check_cap(dev) < 0) {
if (_capture_open_check_cap(cap) < 0) {
goto error;
}
if (_device_apply_resolution(dev, dev->width, dev->height, dev->run->hz)) {
if (_capture_apply_resolution(cap, cap->width, cap->height, cap->run->hz)) {
goto error;
}
if (dev->dv_timings && _device_open_dv_timings(dev, true) < 0) {
if (cap->dv_timings && _capture_open_dv_timings(cap, true) < 0) {
goto error;
}
if (_device_open_format(dev, true) < 0) {
if (_capture_open_format(cap, true) < 0) {
goto error;
}
_device_open_hw_fps(dev);
_device_open_jpeg_quality(dev);
if (_device_open_io_method(dev) < 0) {
_capture_open_hw_fps(cap);
_capture_open_jpeg_quality(cap);
if (_capture_open_io_method(cap) < 0) {
goto error;
}
if (_device_open_queue_buffers(dev) < 0) {
if (_capture_open_queue_buffers(cap) < 0) {
goto error;
}
if (dev->dma_export && !us_is_jpeg(run->format)) {
if (cap->dma_export && !us_is_jpeg(run->format)) {
// uStreamer doesn't have any component that could handle JPEG capture via DMA
run->dma = !_device_open_export_to_dma(dev);
if (!run->dma && dev->dma_required) {
run->dma = !_capture_open_export_to_dma(cap);
if (!run->dma && cap->dma_required) {
goto error;
}
}
_device_apply_controls(dev);
_capture_apply_controls(cap);
enum v4l2_buf_type type = run->capture_type;
if (us_xioctl(run->fd, VIDIOC_STREAMON, &type) < 0) {
@@ -242,17 +242,17 @@ int us_device_open(us_device_s *dev) {
return 0;
tmp_error:
us_device_close(dev);
us_capture_close(cap);
return -2;
error:
run->open_error_reported = 0;
us_device_close(dev);
us_capture_close(cap);
return -1;
}
void us_device_close(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
void us_capture_close(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
bool say = false;
@@ -266,15 +266,15 @@ void us_device_close(us_device_s *dev) {
run->streamon = false;
}
if (run->hw_bufs != NULL) {
if (run->bufs != NULL) {
say = true;
_D_LOG_DEBUG("Releasing HW buffers ...");
for (uint index = 0; index < run->n_bufs; ++index) {
us_hw_buffer_s *hw = &run->hw_bufs[index];
us_capture_hwbuf_s *hw = &run->bufs[index];
US_CLOSE_FD(hw->dma_fd);
if (dev->io_method == V4L2_MEMORY_MMAP) {
if (cap->io_method == V4L2_MEMORY_MMAP) {
if (hw->raw.allocated > 0 && hw->raw.data != NULL) {
if (munmap(hw->raw.data, hw->raw.allocated) < 0) {
_D_LOG_PERROR("Can't unmap HW buffer=%u", index);
@@ -288,7 +288,7 @@ void us_device_close(us_device_s *dev) {
free(hw->buf.m.planes);
}
}
US_DELETE(run->hw_bufs, free);
US_DELETE(run->bufs, free);
run->n_bufs = 0;
}
@@ -299,20 +299,20 @@ void us_device_close(us_device_s *dev) {
}
}
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
int us_capture_grab_buffer(us_capture_s *cap, us_capture_hwbuf_s **hw) {
// Это сложная функция, которая делает сразу много всего, чтобы получить новый фрейм.
// - Вызывается _device_wait_buffer() с select() внутри, чтобы подождать новый фрейм
// - Вызывается _capture_wait_buffer() с select() внутри, чтобы подождать новый фрейм
// или эвент V4L2. Обработка эвентов более приоритетна, чем кадров.
// - Если есть новые фреймы, то пропустить их все, пока не закончатся и вернуть
// самый-самый свежий, содержащий при этом валидные данные.
// - Если таковых не нашлось, вернуть -2.
// - Ошибка -1 возвращается при любых сбоях.
if (_device_wait_buffer(dev) < 0) {
if (_capture_wait_buffer(cap) < 0) {
return -1;
}
us_device_runtime_s *const run = dev->run;
us_capture_runtime_s *const run = cap->run;
*hw = NULL;
@@ -333,7 +333,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
struct v4l2_buffer new = {0};
struct v4l2_plane new_planes[VIDEO_MAX_PLANES] = {0};
new.type = run->capture_type;
new.memory = dev->io_method;
new.memory = cap->io_method;
if (run->capture_mplane) {
new.length = VIDEO_MAX_PLANES;
new.m.planes = new_planes;
@@ -347,8 +347,8 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
return -1;
}
# define GRABBED(x_buf) run->hw_bufs[x_buf.index].grabbed
# define FRAME_DATA(x_buf) run->hw_bufs[x_buf.index].raw.data
# define GRABBED(x_buf) run->bufs[x_buf.index].grabbed
# define FRAME_DATA(x_buf) run->bufs[x_buf.index].raw.data
if (GRABBED(new)) {
_D_LOG_ERROR("V4L2 error: grabbed HW buffer=%u is already used", new.index);
@@ -360,7 +360,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
new.bytesused = new.m.planes[0].bytesused;
}
broken = !_device_is_buffer_valid(dev, &new, FRAME_DATA(new));
broken = !_capture_is_buffer_valid(cap, &new, FRAME_DATA(new));
if (broken) {
_D_LOG_DEBUG("Releasing HW buffer=%u (broken frame) ...", new.index);
if (us_xioctl(run->fd, VIDIOC_QBUF, &new) < 0) {
@@ -400,7 +400,7 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
}
} while (true);
*hw = &run->hw_bufs[buf.index];
*hw = &run->bufs[buf.index];
atomic_store(&(*hw)->refs, 0);
(*hw)->raw.dma_fd = (*hw)->dma_fd;
(*hw)->raw.used = buf.bytesused;
@@ -417,11 +417,11 @@ int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
return buf.index;
}
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) {
int us_capture_release_buffer(us_capture_s *cap, us_capture_hwbuf_s *hw) {
assert(atomic_load(&hw->refs) == 0);
const uint index = hw->buf.index;
_D_LOG_DEBUG("Releasing HW buffer=%u ...", index);
if (us_xioctl(dev->run->fd, VIDIOC_QBUF, &hw->buf) < 0) {
if (us_xioctl(cap->run->fd, VIDIOC_QBUF, &hw->buf) < 0) {
_D_LOG_PERROR("Can't release HW buffer=%u", index);
return -1;
}
@@ -430,16 +430,16 @@ int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) {
return 0;
}
void us_device_buffer_incref(us_hw_buffer_s *hw) {
void us_capture_buffer_incref(us_capture_hwbuf_s *hw) {
atomic_fetch_add(&hw->refs, 1);
}
void us_device_buffer_decref(us_hw_buffer_s *hw) {
void us_capture_buffer_decref(us_capture_hwbuf_s *hw) {
atomic_fetch_sub(&hw->refs, 1);
}
int _device_wait_buffer(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
int _capture_wait_buffer(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
# define INIT_FD_SET(x_set) \
fd_set x_set; FD_ZERO(&x_set); FD_SET(run->fd, &x_set);
@@ -452,7 +452,7 @@ int _device_wait_buffer(us_device_s *dev) {
// has_write не делает никому плохо.
struct timeval timeout;
timeout.tv_sec = dev->timeout;
timeout.tv_sec = cap->timeout;
timeout.tv_usec = 0;
_D_LOG_DEBUG("Calling select() on video device ...");
@@ -475,16 +475,16 @@ int _device_wait_buffer(us_device_s *dev) {
_D_LOG_ERROR("Device select() timeout");
return -1;
} else {
if (has_error && _device_consume_event(dev) < 0) {
if (has_error && _capture_consume_event(cap) < 0) {
return -1; // Restart required
}
}
return 0;
}
static int _device_consume_event(us_device_s *dev) {
static int _capture_consume_event(us_capture_s *cap) {
struct v4l2_event event;
if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) < 0) {
if (us_xioctl(cap->run->fd, VIDIOC_DQEVENT, &event) < 0) {
_D_LOG_PERROR("Can't consume V4L2 event");
return -1;
}
@@ -509,13 +509,13 @@ static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer
}
}
bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, const u8 *data) {
bool _capture_is_buffer_valid(us_capture_s *cap, const struct v4l2_buffer *buf, const u8 *data) {
// Workaround for broken, corrupted frames:
// Under low light conditions corrupted frames may get captured.
// The good thing is such frames are quite small compared to the regular frames.
// For example a VGA (640x480) webcam frame is normally >= 8kByte large,
// corrupted frames are smaller.
if (buf->bytesused < dev->min_frame_size) {
if (buf->bytesused < cap->min_frame_size) {
_D_LOG_DEBUG("Dropped too small frame, assuming it was broken: buffer=%u, bytesused=%u",
buf->index, buf->bytesused);
return false;
@@ -529,7 +529,7 @@ bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, co
// A more sophisticated method would scan for the end of image marker, but
// that takes precious CPU cycles and this should be good enough for most
// cases.
if (us_is_jpeg(dev->run->format)) {
if (us_is_jpeg(cap->run->format)) {
if (buf->bytesused < 125) {
// https://stackoverflow.com/questions/2253404/what-is-the-smallest-valid-jpeg-file-size-in-bytes
_D_LOG_DEBUG("Discarding invalid frame, too small to be a valid JPEG: bytesused=%u", buf->bytesused);
@@ -548,21 +548,21 @@ bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, co
return true;
}
static int _device_open_check_cap(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static int _capture_open_check_cap(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
struct v4l2_capability cap = {0};
struct v4l2_capability cpb = {0};
_D_LOG_DEBUG("Querying device capabilities ...");
if (us_xioctl(run->fd, VIDIOC_QUERYCAP, &cap) < 0) {
if (us_xioctl(run->fd, VIDIOC_QUERYCAP, &cpb) < 0) {
_D_LOG_PERROR("Can't query device capabilities");
return -1;
}
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
if (cpb.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
run->capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
run->capture_mplane = false;
_D_LOG_INFO("Using capture type: single-planar");
} else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
} else if (cpb.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
run->capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
run->capture_mplane = true;
_D_LOG_INFO("Using capture type: multi-planar");
@@ -571,13 +571,13 @@ static int _device_open_check_cap(us_device_s *dev) {
return -1;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
if (!(cpb.capabilities & V4L2_CAP_STREAMING)) {
_D_LOG_ERROR("Device doesn't support streaming IO");
return -1;
}
if (!run->capture_mplane) {
int input = dev->input; // Needs a pointer to int for ioctl()
int input = cap->input; // Needs a pointer to int for ioctl()
_D_LOG_INFO("Using input channel: %d", input);
if (us_xioctl(run->fd, VIDIOC_S_INPUT, &input) < 0) {
_D_LOG_ERROR("Can't set input channel");
@@ -585,9 +585,9 @@ static int _device_open_check_cap(us_device_s *dev) {
}
}
if (dev->standard != V4L2_STD_UNKNOWN) {
_D_LOG_INFO("Using TV standard: %s", _standard_to_string(dev->standard));
if (us_xioctl(run->fd, VIDIOC_S_STD, &dev->standard) < 0) {
if (cap->standard != V4L2_STD_UNKNOWN) {
_D_LOG_INFO("Using TV standard: %s", _standard_to_string(cap->standard));
if (us_xioctl(run->fd, VIDIOC_S_STD, &cap->standard) < 0) {
_D_LOG_ERROR("Can't set video standard");
return -1;
}
@@ -597,10 +597,10 @@ static int _device_open_check_cap(us_device_s *dev) {
return 0;
}
static int _device_open_dv_timings(us_device_s *dev, bool apply) {
static int _capture_open_dv_timings(us_capture_s *cap, bool apply) {
// Just probe only if @apply is false
const us_device_runtime_s *const run = dev->run;
const us_capture_runtime_s *const run = cap->run;
int dv_errno = 0;
@@ -637,14 +637,14 @@ static int _device_open_dv_timings(us_device_s *dev, bool apply) {
_D_LOG_PERROR("Failed to apply DV-timings");
return -1;
}
if (_device_apply_resolution(dev, dv.bt.width, dv.bt.height, hz) < 0) {
if (_capture_apply_resolution(cap, dv.bt.width, dv.bt.height, hz) < 0) {
return -1;
}
goto subscribe;
querystd:
_D_LOG_DEBUG("Failed to query DV-timings, trying QuerySTD ...");
if (us_xioctl(run->fd, VIDIOC_QUERYSTD, &dev->standard) < 0) {
if (us_xioctl(run->fd, VIDIOC_QUERYSTD, &cap->standard) < 0) {
if (apply) {
char *std_error = us_errno_to_string(errno); // Read the errno first
char *dv_error = us_errno_to_string(dv_errno);
@@ -656,17 +656,17 @@ querystd:
} else if (!apply) {
goto probe_only;
}
if (us_xioctl(run->fd, VIDIOC_S_STD, &dev->standard) < 0) {
_D_LOG_PERROR("Can't set apply standard: %s", _standard_to_string(dev->standard));
if (us_xioctl(run->fd, VIDIOC_S_STD, &cap->standard) < 0) {
_D_LOG_PERROR("Can't set apply standard: %s", _standard_to_string(cap->standard));
return -1;
}
_D_LOG_DEBUG("Applied new video standard: %s", _standard_to_string(dev->standard));
_D_LOG_DEBUG("Applied new video standard: %s", _standard_to_string(cap->standard));
subscribe:
; // Empty statement for the goto label above
struct v4l2_event_subscription sub = {.type = V4L2_EVENT_SOURCE_CHANGE};
_D_LOG_DEBUG("Subscribing to V4L2_EVENT_SOURCE_CHANGE ...")
if (us_xioctl(dev->run->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) {
if (us_xioctl(cap->run->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) {
_D_LOG_PERROR("Can't subscribe to V4L2_EVENT_SOURCE_CHANGE");
return -1;
}
@@ -675,8 +675,8 @@ probe_only:
return 0;
}
static int _device_open_format(us_device_s *dev, bool first) {
us_device_runtime_s *const run = dev->run;
static int _capture_open_format(us_capture_s *cap, bool first) {
us_capture_runtime_s *const run = cap->run;
const uint stride = us_align_size(run->width, 32) << 1;
@@ -685,21 +685,21 @@ static int _device_open_format(us_device_s *dev, bool first) {
if (run->capture_mplane) {
fmt.fmt.pix_mp.width = run->width;
fmt.fmt.pix_mp.height = run->height;
fmt.fmt.pix_mp.pixelformat = dev->format;
fmt.fmt.pix_mp.pixelformat = cap->format;
fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
fmt.fmt.pix_mp.flags = 0;
fmt.fmt.pix_mp.num_planes = 1;
} else {
fmt.fmt.pix.width = run->width;
fmt.fmt.pix.height = run->height;
fmt.fmt.pix.pixelformat = dev->format;
fmt.fmt.pix.pixelformat = cap->format;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
fmt.fmt.pix.bytesperline = stride;
}
// Set format
_D_LOG_DEBUG("Probing device format=%s, stride=%u, resolution=%ux%u ...",
_format_to_string_supported(dev->format), stride, run->width, run->height);
_format_to_string_supported(cap->format), stride, run->width, run->height);
if (us_xioctl(run->fd, VIDIOC_S_FMT, &fmt) < 0) {
_D_LOG_PERROR("Can't set device format");
return -1;
@@ -719,18 +719,18 @@ static int _device_open_format(us_device_s *dev, bool first) {
_D_LOG_ERROR("Requested resolution=%ux%u is unavailable", run->width, run->height);
retry = true;
}
if (_device_apply_resolution(dev, FMT(width), FMT(height), run->hz) < 0) {
if (_capture_apply_resolution(cap, FMT(width), FMT(height), run->hz) < 0) {
return -1;
}
if (first && retry) {
return _device_open_format(dev, false);
return _capture_open_format(cap, false);
}
_D_LOG_INFO("Using resolution: %ux%u", run->width, run->height);
// Check format
if (FMT(pixelformat) != dev->format) {
if (FMT(pixelformat) != cap->format) {
_D_LOG_ERROR("Could not obtain the requested format=%s; driver gave us %s",
_format_to_string_supported(dev->format),
_format_to_string_supported(cap->format),
_format_to_string_supported(FMT(pixelformat)));
char *format_str;
@@ -747,6 +747,21 @@ static int _device_open_format(us_device_s *dev, bool first) {
run->format = FMT(pixelformat);
_D_LOG_INFO("Using format: %s", _format_to_string_supported(run->format));
if (cap->format_swap_rgb) {
// Userspace workaround for TC358743 RGB/BGR bug:
// - https://github.com/raspberrypi/linux/issues/6068
uint swapped = 0;
switch (run->format) {
case V4L2_PIX_FMT_RGB24: swapped = V4L2_PIX_FMT_BGR24; break;
case V4L2_PIX_FMT_BGR24: swapped = V4L2_PIX_FMT_RGB24; break;
}
if (swapped > 0) {
_D_LOG_INFO("Using format swap: %s -> %s",
_format_to_string_supported(run->format),
_format_to_string_supported(swapped));
run->format = swapped;
}
}
run->stride = FMTS(bytesperline);
run->raw_size = FMTS(sizeimage); // Only for userptr
@@ -757,8 +772,8 @@ static int _device_open_format(us_device_s *dev, bool first) {
return 0;
}
static void _device_open_hw_fps(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static void _capture_open_hw_fps(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
run->hw_fps = 0;
@@ -783,7 +798,7 @@ static void _device_open_hw_fps(us_device_s *dev) {
US_MEMSET_ZERO(setfps);
setfps.type = run->capture_type;
SETFPS_TPF(numerator) = 1;
SETFPS_TPF(denominator) = (dev->desired_fps == 0 ? 255 : dev->desired_fps);
SETFPS_TPF(denominator) = (cap->desired_fps == 0 ? 255 : cap->desired_fps);
if (us_xioctl(run->fd, VIDIOC_S_PARM, &setfps) < 0) {
_D_LOG_PERROR("Can't set HW FPS");
@@ -801,8 +816,8 @@ static void _device_open_hw_fps(us_device_s *dev) {
}
run->hw_fps = SETFPS_TPF(denominator);
if (dev->desired_fps != run->hw_fps) {
_D_LOG_INFO("Using HW FPS: %u -> %u (coerced)", dev->desired_fps, run->hw_fps);
if (cap->desired_fps != run->hw_fps) {
_D_LOG_INFO("Using HW FPS: %u -> %u (coerced)", cap->desired_fps, run->hw_fps);
} else {
_D_LOG_INFO("Using HW FPS: %u", run->hw_fps);
}
@@ -810,46 +825,46 @@ static void _device_open_hw_fps(us_device_s *dev) {
# undef SETFPS_TPF
}
static void _device_open_jpeg_quality(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static void _capture_open_jpeg_quality(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
uint quality = 0;
if (us_is_jpeg(run->format)) {
struct v4l2_jpegcompression comp = {0};
if (us_xioctl(run->fd, VIDIOC_G_JPEGCOMP, &comp) < 0) {
_D_LOG_ERROR("Device doesn't support setting of HW encoding quality parameters");
} else {
comp.quality = dev->jpeg_quality;
comp.quality = cap->jpeg_quality;
if (us_xioctl(run->fd, VIDIOC_S_JPEGCOMP, &comp) < 0) {
_D_LOG_ERROR("Can't change MJPEG quality for JPEG source with HW pass-through encoder");
} else {
quality = dev->jpeg_quality;
quality = cap->jpeg_quality;
}
}
}
run->jpeg_quality = quality;
}
static int _device_open_io_method(us_device_s *dev) {
_D_LOG_INFO("Using IO method: %s", _io_method_to_string_supported(dev->io_method));
switch (dev->io_method) {
case V4L2_MEMORY_MMAP: return _device_open_io_method_mmap(dev);
case V4L2_MEMORY_USERPTR: return _device_open_io_method_userptr(dev);
static int _capture_open_io_method(us_capture_s *cap) {
_D_LOG_INFO("Using IO method: %s", _io_method_to_string_supported(cap->io_method));
switch (cap->io_method) {
case V4L2_MEMORY_MMAP: return _capture_open_io_method_mmap(cap);
case V4L2_MEMORY_USERPTR: return _capture_open_io_method_userptr(cap);
default: assert(0 && "Unsupported IO method");
}
return -1;
}
static int _device_open_io_method_mmap(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static int _capture_open_io_method_mmap(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
struct v4l2_requestbuffers req = {
.count = dev->n_bufs,
.count = cap->n_bufs,
.type = run->capture_type,
.memory = V4L2_MEMORY_MMAP,
};
_D_LOG_DEBUG("Requesting %u device buffers for MMAP ...", req.count);
if (us_xioctl(run->fd, VIDIOC_REQBUFS, &req) < 0) {
_D_LOG_PERROR("Device '%s' doesn't support MMAP method", dev->path);
_D_LOG_PERROR("Device '%s' doesn't support MMAP method", cap->path);
return -1;
}
@@ -857,12 +872,12 @@ static int _device_open_io_method_mmap(us_device_s *dev) {
_D_LOG_ERROR("Insufficient buffer memory: %u", req.count);
return -1;
} else {
_D_LOG_INFO("Requested %u device buffers, got %u", dev->n_bufs, req.count);
_D_LOG_INFO("Requested %u device buffers, got %u", cap->n_bufs, req.count);
}
_D_LOG_DEBUG("Allocating device buffers ...");
US_CALLOC(run->hw_bufs, req.count);
US_CALLOC(run->bufs, req.count);
for (run->n_bufs = 0; run->n_bufs < req.count; ++run->n_bufs) {
struct v4l2_buffer buf = {0};
@@ -881,7 +896,7 @@ static int _device_open_io_method_mmap(us_device_s *dev) {
return -1;
}
us_hw_buffer_s *hw = &run->hw_bufs[run->n_bufs];
us_capture_hwbuf_s *hw = &run->bufs[run->n_bufs];
atomic_init(&hw->refs, 0);
const uz buf_size = (run->capture_mplane ? buf.m.planes[0].length : buf.length);
const off_t buf_offset = (run->capture_mplane ? buf.m.planes[0].m.mem_offset : buf.m.offset);
@@ -907,17 +922,17 @@ static int _device_open_io_method_mmap(us_device_s *dev) {
return 0;
}
static int _device_open_io_method_userptr(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static int _capture_open_io_method_userptr(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
struct v4l2_requestbuffers req = {
.count = dev->n_bufs,
.count = cap->n_bufs,
.type = run->capture_type,
.memory = V4L2_MEMORY_USERPTR,
};
_D_LOG_DEBUG("Requesting %u device buffers for USERPTR ...", req.count);
if (us_xioctl(run->fd, VIDIOC_REQBUFS, &req) < 0) {
_D_LOG_PERROR("Device '%s' doesn't support USERPTR method", dev->path);
_D_LOG_PERROR("Device '%s' doesn't support USERPTR method", cap->path);
return -1;
}
@@ -925,18 +940,18 @@ static int _device_open_io_method_userptr(us_device_s *dev) {
_D_LOG_ERROR("Insufficient buffer memory: %u", req.count);
return -1;
} else {
_D_LOG_INFO("Requested %u device buffers, got %u", dev->n_bufs, req.count);
_D_LOG_INFO("Requested %u device buffers, got %u", cap->n_bufs, req.count);
}
_D_LOG_DEBUG("Allocating device buffers ...");
US_CALLOC(run->hw_bufs, req.count);
US_CALLOC(run->bufs, req.count);
const uint page_size = getpagesize();
const uint buf_size = us_align_size(run->raw_size, page_size);
for (run->n_bufs = 0; run->n_bufs < req.count; ++run->n_bufs) {
us_hw_buffer_s *hw = &run->hw_bufs[run->n_bufs];
us_capture_hwbuf_s *hw = &run->bufs[run->n_bufs];
assert((hw->raw.data = aligned_alloc(page_size, buf_size)) != NULL);
memset(hw->raw.data, 0, buf_size);
hw->raw.allocated = buf_size;
@@ -947,25 +962,25 @@ static int _device_open_io_method_userptr(us_device_s *dev) {
return 0;
}
static int _device_open_queue_buffers(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static int _capture_open_queue_buffers(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
for (uint index = 0; index < run->n_bufs; ++index) {
struct v4l2_buffer buf = {0};
struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0};
buf.type = run->capture_type;
buf.memory = dev->io_method;
buf.memory = cap->io_method;
buf.index = index;
if (run->capture_mplane) {
buf.m.planes = planes;
buf.length = 1;
}
if (dev->io_method == V4L2_MEMORY_USERPTR) {
if (cap->io_method == V4L2_MEMORY_USERPTR) {
// I am not sure, may be this is incorrect for mplane device,
// but i don't have one which supports V4L2_MEMORY_USERPTR
buf.m.userptr = (unsigned long)run->hw_bufs[index].raw.data;
buf.length = run->hw_bufs[index].raw.allocated;
buf.m.userptr = (unsigned long)run->bufs[index].raw.data;
buf.length = run->bufs[index].raw.allocated;
}
_D_LOG_DEBUG("Calling us_xioctl(VIDIOC_QBUF) for buffer=%u ...", index);
@@ -977,8 +992,8 @@ static int _device_open_queue_buffers(us_device_s *dev) {
return 0;
}
static int _device_open_export_to_dma(us_device_s *dev) {
us_device_runtime_s *const run = dev->run;
static int _capture_open_export_to_dma(us_capture_s *cap) {
us_capture_runtime_s *const run = cap->run;
for (uint index = 0; index < run->n_bufs; ++index) {
struct v4l2_exportbuffer exp = {
@@ -990,18 +1005,18 @@ static int _device_open_export_to_dma(us_device_s *dev) {
_D_LOG_PERROR("Can't export device buffer=%u to DMA", index);
goto error;
}
run->hw_bufs[index].dma_fd = exp.fd;
run->bufs[index].dma_fd = exp.fd;
}
return 0;
error:
for (uint index = 0; index < run->n_bufs; ++index) {
US_CLOSE_FD(run->hw_bufs[index].dma_fd);
US_CLOSE_FD(run->bufs[index].dma_fd);
}
return -1;
}
static int _device_apply_resolution(us_device_s *dev, uint width, uint height, float hz) {
static int _capture_apply_resolution(us_capture_s *cap, uint width, uint height, float hz) {
// Тут VIDEO_MIN_* не используются из-за странностей минимального разрешения при отсутствии сигнала
// у некоторых устройств, например TC358743
if (
@@ -1012,42 +1027,42 @@ static int _device_apply_resolution(us_device_s *dev, uint width, uint height, f
width, height, US_VIDEO_MAX_WIDTH, US_VIDEO_MAX_HEIGHT);
return -1;
}
dev->run->width = width;
dev->run->height = height;
dev->run->hz = hz;
cap->run->width = width;
cap->run->height = height;
cap->run->hz = hz;
return 0;
}
static void _device_apply_controls(us_device_s *dev) {
static void _capture_apply_controls(us_capture_s *cap) {
# define SET_CID_VALUE(x_cid, x_field, x_value, x_quiet) { \
struct v4l2_queryctrl m_query; \
if (_device_query_control(dev, &m_query, #x_field, x_cid, x_quiet) == 0) { \
_device_set_control(dev, &m_query, #x_field, x_cid, x_value, x_quiet); \
if (_capture_query_control(cap, &m_query, #x_field, x_cid, x_quiet) == 0) { \
_capture_set_control(cap, &m_query, #x_field, x_cid, x_value, x_quiet); \
} \
}
# define SET_CID_DEFAULT(x_cid, x_field, x_quiet) { \
struct v4l2_queryctrl m_query; \
if (_device_query_control(dev, &m_query, #x_field, x_cid, x_quiet) == 0) { \
_device_set_control(dev, &m_query, #x_field, x_cid, m_query.default_value, x_quiet); \
if (_capture_query_control(cap, &m_query, #x_field, x_cid, x_quiet) == 0) { \
_capture_set_control(cap, &m_query, #x_field, x_cid, m_query.default_value, x_quiet); \
} \
}
# define CONTROL_MANUAL_CID(x_cid, x_field) { \
if (dev->ctl.x_field.mode == CTL_MODE_VALUE) { \
SET_CID_VALUE(x_cid, x_field, dev->ctl.x_field.value, false); \
} else if (dev->ctl.x_field.mode == CTL_MODE_DEFAULT) { \
if (cap->ctl.x_field.mode == CTL_MODE_VALUE) { \
SET_CID_VALUE(x_cid, x_field, cap->ctl.x_field.value, false); \
} else if (cap->ctl.x_field.mode == CTL_MODE_DEFAULT) { \
SET_CID_DEFAULT(x_cid, x_field, false); \
} \
}
# define CONTROL_AUTO_CID(x_cid_auto, x_cid_manual, x_field) { \
if (dev->ctl.x_field.mode == CTL_MODE_VALUE) { \
if (cap->ctl.x_field.mode == CTL_MODE_VALUE) { \
SET_CID_VALUE(x_cid_auto, x_field##_auto, 0, true); \
SET_CID_VALUE(x_cid_manual, x_field, dev->ctl.x_field.value, false); \
} else if (dev->ctl.x_field.mode == CTL_MODE_AUTO) { \
SET_CID_VALUE(x_cid_manual, x_field, cap->ctl.x_field.value, false); \
} else if (cap->ctl.x_field.mode == CTL_MODE_AUTO) { \
SET_CID_VALUE(x_cid_auto, x_field##_auto, 1, false); \
} else if (dev->ctl.x_field.mode == CTL_MODE_DEFAULT) { \
} else if (cap->ctl.x_field.mode == CTL_MODE_DEFAULT) { \
SET_CID_VALUE(x_cid_auto, x_field##_auto, 0, true); /* Reset inactive flag */ \
SET_CID_DEFAULT(x_cid_manual, x_field, false); \
SET_CID_DEFAULT(x_cid_auto, x_field##_auto, false); \
@@ -1074,15 +1089,15 @@ static void _device_apply_controls(us_device_s *dev) {
# undef SET_CID_VALUE
}
static int _device_query_control(
us_device_s *dev, struct v4l2_queryctrl *query,
static int _capture_query_control(
us_capture_s *cap, struct v4l2_queryctrl *query,
const char *name, uint cid, bool quiet) {
// cppcheck-suppress redundantPointerOp
US_MEMSET_ZERO(*query);
query->id = cid;
if (us_xioctl(dev->run->fd, VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) {
if (us_xioctl(cap->run->fd, VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) {
if (!quiet) {
_D_LOG_ERROR("Changing control %s is unsupported", name);
}
@@ -1091,8 +1106,8 @@ static int _device_query_control(
return 0;
}
static void _device_set_control(
us_device_s *dev, const struct v4l2_queryctrl *query,
static void _capture_set_control(
us_capture_s *cap, const struct v4l2_queryctrl *query,
const char *name, uint cid, int value, bool quiet) {
if (value < query->minimum || value > query->maximum || value % query->step != 0) {
@@ -1107,7 +1122,7 @@ static void _device_set_control(
.id = cid,
.value = value,
};
if (us_xioctl(dev->run->fd, VIDIOC_S_CTRL, &ctl) < 0) {
if (us_xioctl(cap->run->fd, VIDIOC_S_CTRL, &ctl) < 0) {
if (!quiet) {
_D_LOG_PERROR("Can't set control %s", name);
}

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -49,7 +49,7 @@ typedef struct {
int dma_fd;
bool grabbed;
atomic_int refs;
} us_hw_buffer_s;
} us_capture_hwbuf_s;
typedef struct {
int fd;
@@ -62,13 +62,13 @@ typedef struct {
uint jpeg_quality;
uz raw_size;
uint n_bufs;
us_hw_buffer_s *hw_bufs;
us_capture_hwbuf_s *bufs;
bool dma;
enum v4l2_buf_type capture_type;
bool capture_mplane;
bool streamon;
int open_error_reported;
} us_device_runtime_s;
} us_capture_runtime_s;
typedef enum {
CTL_MODE_NONE = 0,
@@ -104,6 +104,8 @@ typedef struct {
uint width;
uint height;
uint format;
bool format_swap_rgb;
uint jpeg_quality;
v4l2_std_id standard;
enum v4l2_memory io_method;
@@ -116,22 +118,22 @@ typedef struct {
bool persistent;
uint timeout;
us_controls_s ctl;
us_device_runtime_s *run;
} us_device_s;
us_capture_runtime_s *run;
} us_capture_s;
us_device_s *us_device_init(void);
void us_device_destroy(us_device_s *dev);
us_capture_s *us_capture_init(void);
void us_capture_destroy(us_capture_s *cap);
int us_device_parse_format(const char *str);
int us_device_parse_standard(const char *str);
int us_device_parse_io_method(const char *str);
int us_capture_parse_format(const char *str);
int us_capture_parse_standard(const char *str);
int us_capture_parse_io_method(const char *str);
int us_device_open(us_device_s *dev);
void us_device_close(us_device_s *dev);
int us_capture_open(us_capture_s *cap);
void us_capture_close(us_capture_s *cap);
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw);
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw);
int us_capture_grab_buffer(us_capture_s *cap, us_capture_hwbuf_s **hw);
int us_capture_release_buffer(us_capture_s *cap, us_capture_hwbuf_s *hw);
void us_device_buffer_incref(us_hw_buffer_s *hw);
void us_device_buffer_decref(us_hw_buffer_s *hw);
void us_capture_buffer_incref(us_capture_hwbuf_s *hw);
void us_capture_buffer_decref(us_capture_hwbuf_s *hw);

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -26,7 +26,7 @@
#define US_VERSION_MAJOR 6
#define US_VERSION_MINOR 4
#define US_VERSION_MINOR 8
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -37,17 +37,18 @@
#include <drm_fourcc.h>
#include <libdrm/drm.h>
#include "../libs/types.h"
#include "../libs/tools.h"
#include "../libs/logging.h"
#include "../libs/frame.h"
#include "../libs/frametext.h"
#include "../types.h"
#include "../tools.h"
#include "../logging.h"
#include "../frame.h"
#include "../frametext.h"
#include "../capture.h"
static void _drm_vsync_callback(int fd, uint n_frame, uint sec, uint usec, void *v_buf);
static int _drm_check_status(us_drm_s *drm);
static void _drm_ensure_dpms_power(us_drm_s *drm, bool on);
static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev);
static int _drm_init_buffers(us_drm_s *drm, const us_capture_s *cap);
static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz);
static drmModeModeInfo *_find_best_mode(drmModeConnector *conn, uint width, uint height, float hz);
@@ -78,7 +79,7 @@ us_drm_s *us_drm_init(void) {
US_CALLOC(drm, 1);
// drm->path = "/dev/dri/card0";
drm->path = "/dev/dri/by-path/platform-gpu-card";
drm->port = "HDMI-A-1";
drm->port = "HDMI-A-2"; // OUT2 on PiKVM V4 Plus
drm->timeout = 5;
drm->run = run;
return drm;
@@ -90,7 +91,7 @@ void us_drm_destroy(us_drm_s *drm) {
US_DELETE(drm, free); // cppcheck-suppress uselessAssignmentPtrArg
}
int us_drm_open(us_drm_s *drm, const us_device_s *dev) {
int us_drm_open(us_drm_s *drm, const us_capture_s *cap) {
us_drm_runtime_s *const run = drm->run;
assert(run->fd < 0);
@@ -101,7 +102,7 @@ int us_drm_open(us_drm_s *drm, const us_device_s *dev) {
default: goto error;
}
_D_LOG_INFO("Configuring DRM device for %s ...", (dev == NULL ? "STUB" : "DMA"));
_D_LOG_INFO("Configuring DRM device for %s ...", (cap == NULL ? "STUB" : "DMA"));
if ((run->fd = open(drm->path, O_RDWR | O_CLOEXEC | O_NONBLOCK)) < 0) {
_D_LOG_PERROR("Can't open DRM device");
@@ -110,12 +111,12 @@ int us_drm_open(us_drm_s *drm, const us_device_s *dev) {
_D_LOG_DEBUG("DRM device fd=%d opened", run->fd);
int stub = 0; // Open the real device with DMA
if (dev == NULL) {
if (cap == NULL) {
stub = US_DRM_STUB_USER;
} else if (dev->run->format != V4L2_PIX_FMT_RGB24) {
} else if (cap->run->format != V4L2_PIX_FMT_RGB24 && cap->run->format != V4L2_PIX_FMT_BGR24) {
stub = US_DRM_STUB_BAD_FORMAT;
char fourcc_str[8];
us_fourcc_to_string(dev->run->format, fourcc_str, 8);
us_fourcc_to_string(cap->run->format, fourcc_str, 8);
_D_LOG_ERROR("Input format %s is not supported, forcing to STUB ...", fourcc_str);
}
@@ -137,9 +138,9 @@ int us_drm_open(us_drm_s *drm, const us_device_s *dev) {
}
# undef CHECK_CAP
const uint width = (stub > 0 ? 0 : dev->run->width);
const uint height = (stub > 0 ? 0 : dev->run->height);
const uint hz = (stub > 0 ? 0 : dev->run->hz);
const uint width = (stub > 0 ? 0 : cap->run->width);
const uint height = (stub > 0 ? 0 : cap->run->height);
const uint hz = (stub > 0 ? 0 : cap->run->hz);
switch (_drm_find_sink(drm, width, height, hz)) {
case 0: break;
case -2: goto unplugged;
@@ -151,7 +152,7 @@ int us_drm_open(us_drm_s *drm, const us_device_s *dev) {
_D_LOG_ERROR("There is no appropriate modes for the capture, forcing to STUB ...");
}
if (_drm_init_buffers(drm, (stub > 0 ? NULL : dev)) < 0) {
if (_drm_init_buffers(drm, (stub > 0 ? NULL : cap)) < 0) {
goto error;
}
@@ -308,7 +309,7 @@ static void _drm_vsync_callback(int fd, uint n_frame, uint sec, uint usec, void
_D_LOG_DEBUG("Got VSync signal");
}
int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_device_s *dev) {
int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_capture_s *cap) {
us_drm_runtime_s *const run = drm->run;
assert(run->fd >= 0);
@@ -324,14 +325,14 @@ int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_device_s *dev
# define DRAW_MSG(x_msg) us_frametext_draw(run->ft, (x_msg), run->mode.hdisplay, run->mode.vdisplay)
switch (stub) {
case US_DRM_STUB_BAD_RESOLUTION: {
assert(dev != NULL);
assert(cap != NULL);
char msg[1024];
US_SNPRINTF(msg, 1023,
"=== PiKVM ==="
"\n \n< UNSUPPORTED RESOLUTION >"
"\n \n< %ux%up%.02f >"
"\n \nby this display",
dev->run->width, dev->run->height, dev->run->hz);
cap->run->width, cap->run->height, cap->run->hz);
DRAW_MSG(msg);
break;
};
@@ -376,7 +377,7 @@ int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_device_s *dev
return retval;
}
int us_drm_expose_dma(us_drm_s *drm, const us_hw_buffer_s *hw) {
int us_drm_expose_dma(us_drm_s *drm, const us_capture_hwbuf_s *hw) {
us_drm_runtime_s *const run = drm->run;
us_drm_buffer_s *const buf = &run->bufs[hw->buf.index];
@@ -459,14 +460,16 @@ static void _drm_ensure_dpms_power(us_drm_s *drm, bool on) {
run->dpms_state = (int)on;
}
static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
static int _drm_init_buffers(us_drm_s *drm, const us_capture_s *cap) {
us_drm_runtime_s *const run = drm->run;
const uint n_bufs = (dev == NULL ? 4 : dev->run->n_bufs);
const char *name = (dev == NULL ? "STUB" : "DMA");
const uint n_bufs = (cap == NULL ? 4 : cap->run->n_bufs);
const char *name = (cap == NULL ? "STUB" : "DMA");
_D_LOG_DEBUG("Initializing %u %s buffers ...", n_bufs, name);
uint format = DRM_FORMAT_RGB888;
US_CALLOC(run->bufs, n_bufs);
for (run->n_bufs = 0; run->n_bufs < n_bufs; ++run->n_bufs) {
const uint n_buf = run->n_bufs;
@@ -479,7 +482,7 @@ static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
u32 strides[4] = {0};
u32 offsets[4] = {0};
if (dev == NULL) {
if (cap == NULL) {
struct drm_mode_create_dumb create = {
.width = run->mode.hdisplay,
.height = run->mode.vdisplay,
@@ -512,17 +515,22 @@ static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
strides[0] = create.pitch;
} else {
if (drmPrimeFDToHandle(run->fd, dev->run->hw_bufs[n_buf].dma_fd, &buf->handle) < 0) {
if (drmPrimeFDToHandle(run->fd, cap->run->bufs[n_buf].dma_fd, &buf->handle) < 0) {
_D_LOG_PERROR("Can't import DMA buffer=%u from capture device", n_buf);
return -1;
}
handles[0] = buf->handle;
strides[0] = dev->run->stride;
strides[0] = cap->run->stride;
switch (cap->run->format) {
case V4L2_PIX_FMT_RGB24: format = (DRM_FORMAT_BIG_ENDIAN ? DRM_FORMAT_BGR888 : DRM_FORMAT_RGB888); break;
case V4L2_PIX_FMT_BGR24: format = (DRM_FORMAT_BIG_ENDIAN ? DRM_FORMAT_RGB888 : DRM_FORMAT_BGR888); break;
}
}
if (drmModeAddFB2(
run->fd,
run->mode.hdisplay, run->mode.vdisplay, DRM_FORMAT_RGB888,
run->mode.hdisplay, run->mode.vdisplay, format,
handles, strides, offsets, &buf->id, 0
)) {
_D_LOG_PERROR("Can't setup buffer=%u", n_buf);

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -25,10 +25,10 @@
#include <xf86drmMode.h>
#include "../libs/types.h"
#include "../libs/frame.h"
#include "../libs/frametext.h"
#include "../libs/device.h"
#include "../types.h"
#include "../frame.h"
#include "../frametext.h"
#include "../capture.h"
typedef enum {
@@ -83,10 +83,10 @@ typedef struct {
us_drm_s *us_drm_init(void);
void us_drm_destroy(us_drm_s *drm);
int us_drm_open(us_drm_s *drm, const us_device_s *dev);
int us_drm_open(us_drm_s *drm, const us_capture_s *cap);
void us_drm_close(us_drm_s *drm);
int us_drm_dpms_power_off(us_drm_s *drm);
int us_drm_wait_for_vsync(us_drm_s *drm);
int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_device_s *dev);
int us_drm_expose_dma(us_drm_s *drm, const us_hw_buffer_s *hw);
int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_capture_s *cap);
int us_drm_expose_dma(us_drm_s *drm, const us_capture_hwbuf_s *hw);

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -56,6 +56,11 @@ us_memsink_s *us_memsink_init(
US_LOG_INFO("Using %s-sink: %s", name, obj);
if ((sink->data_size = us_memsink_calculate_size(obj)) == 0) {
US_LOG_ERROR("%s-sink: Invalid object suffix", name);
goto error;
}
const mode_t mask = umask(0);
sink->fd = shm_open(sink->obj, (server ? O_RDWR | O_CREAT : O_RDWR), mode);
umask(mask);
@@ -65,12 +70,12 @@ us_memsink_s *us_memsink_init(
goto error;
}
if (sink->server && ftruncate(sink->fd, sizeof(us_memsink_shared_s)) < 0) {
if (sink->server && ftruncate(sink->fd, sizeof(us_memsink_shared_s) + sink->data_size) < 0) {
US_LOG_PERROR("%s-sink: Can't truncate shared memory", name);
goto error;
}
if ((sink->mem = us_memsink_shared_map(sink->fd)) == NULL) {
if ((sink->mem = us_memsink_shared_map(sink->fd, sink->data_size)) == NULL) {
US_LOG_PERROR("%s-sink: Can't mmap shared memory", name);
goto error;
}
@@ -83,7 +88,7 @@ error:
void us_memsink_destroy(us_memsink_s *sink) {
if (sink->mem != NULL) {
if (us_memsink_shared_unmap(sink->mem) < 0) {
if (us_memsink_shared_unmap(sink->mem, sink->data_size) < 0) {
US_LOG_PERROR("%s-sink: Can't unmap shared memory", sink->name);
}
}
@@ -160,9 +165,9 @@ int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key
const ldf now = us_get_now_monotonic();
if (frame->used > US_MEMSINK_MAX_DATA) {
if (frame->used > sink->data_size) {
US_LOG_ERROR("%s-sink: Can't put frame: is too big (%zu > %zu)",
sink->name, frame->used, US_MEMSINK_MAX_DATA);
sink->name, frame->used, sink->data_size);
return 0; // -2
}
@@ -177,7 +182,7 @@ int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key
*key_requested = sink->mem->key_requested;
}
memcpy(sink->mem->data, frame->data, frame->used);
memcpy(us_memsink_get_data(sink->mem), frame->data, frame->used);
sink->mem->used = frame->used;
US_FRAME_COPY_META(frame, sink->mem);
@@ -236,7 +241,7 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_reque
}
sink->last_readed_id = sink->mem->id;
us_frame_set_data(frame, sink->mem->data, sink->mem->used);
us_frame_set_data(frame, us_memsink_get_data(sink->mem), sink->mem->used);
US_FRAME_COPY_META(sink->mem, frame);
if (key_requested != NULL) { // We don't need it for non-H264 sinks
*key_requested = sink->mem->key_requested;

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -34,6 +34,7 @@
typedef struct {
const char *name;
const char *obj;
uz data_size;
bool server;
bool rm;
uint client_ttl; // Only for server

72
src/libs/memsinksh.c Normal file
View File

@@ -0,0 +1,72 @@
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2024 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/>. #
# #
*****************************************************************************/
#include "memsinksh.h"
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <sys/mman.h>
#include "types.h"
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) {
us_memsink_shared_s *mem = mmap(
NULL,
sizeof(us_memsink_shared_s) + data_size,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
if (mem == MAP_FAILED) {
return NULL;
}
assert(mem != NULL);
return mem;
}
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size) {
assert(mem != NULL);
return munmap(mem, sizeof(us_memsink_shared_s) + data_size);
}
uz us_memsink_calculate_size(const char *obj) {
const char *ptr = strrchr(obj, ':');
if (ptr == NULL) {
ptr = strrchr(obj, '.');
}
if (ptr != NULL) {
ptr += 1;
if (!strcasecmp(ptr, "jpeg")) {
return 4 * 1024 * 1024;
} else if (!strcasecmp(ptr, "h264")) {
return 2 * 1024 * 1024;
} else if (!strcasecmp(ptr, "raw")) {
return 1920 * 1200 * 3; // RGB
}
}
return 0;
}
u8 *us_memsink_get_data(us_memsink_shared_s *mem) {
return (u8*)(mem) + sizeof(us_memsink_shared_s);
}

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -22,18 +22,11 @@
#pragma once
#include <sys/mman.h>
#include "types.h"
#define US_MEMSINK_MAGIC ((u64)0xCAFEBABECAFEBABE)
#define US_MEMSINK_VERSION ((u32)4)
#ifndef US_CFG_MEMSINK_MAX_DATA
# define US_CFG_MEMSINK_MAX_DATA 33554432
#endif
#define US_MEMSINK_MAX_DATA ((uz)(US_CFG_MEMSINK_MAX_DATA))
#define US_MEMSINK_VERSION ((u32)6)
typedef struct {
@@ -57,28 +50,11 @@ typedef struct {
ldf last_client_ts;
bool key_requested;
u8 data[US_MEMSINK_MAX_DATA];
} us_memsink_shared_s;
INLINE us_memsink_shared_s *us_memsink_shared_map(int fd) {
us_memsink_shared_s *mem = mmap(
NULL,
sizeof(us_memsink_shared_s),
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
if (mem == MAP_FAILED) {
return NULL;
}
assert(mem != NULL);
return mem;
}
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size);
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size);
INLINE int us_memsink_shared_unmap(us_memsink_shared_s *mem) {
assert(mem != NULL);
return munmap(mem, sizeof(us_memsink_shared_s));
}
uz us_memsink_calculate_size(const char *obj);
u8 *us_memsink_get_data(us_memsink_shared_s *mem);

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -84,7 +84,7 @@ INLINE void us_thread_set_name(const char *name) {
# elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
pthread_set_name_np(pthread_self(), name);
# elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void *)name);
pthread_setname_np(pthread_self(), "%s", (void*)name);
# else
# error us_thread_set_name() not implemented, you can disable it using WITH_PTHREAD_NP=0
# endif

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -91,13 +91,13 @@ const char *us_encoder_type_to_string(us_encoder_type_e type) {
return _ENCODER_TYPES[0].name;
}
void us_encoder_open(us_encoder_s *enc, us_device_s *dev) {
void us_encoder_open(us_encoder_s *enc, us_capture_s *cap) {
assert(enc->run->pool == NULL);
# define DR(x_next) dev->run->x_next
# define DR(x_next) cap->run->x_next
us_encoder_type_e type = (_ER(cpu_forced) ? US_ENCODER_TYPE_CPU : enc->type);
unsigned quality = dev->jpeg_quality;
unsigned quality = cap->jpeg_quality;
unsigned n_workers = US_MIN(enc->n_workers, DR(n_bufs));
bool cpu_forced = false;
@@ -139,7 +139,7 @@ void us_encoder_open(us_encoder_s *enc, us_device_s *dev) {
use_cpu:
type = US_ENCODER_TYPE_CPU;
quality = dev->jpeg_quality;
quality = cap->jpeg_quality;
ok:
if (type == US_ENCODER_TYPE_NOOP) {
@@ -159,14 +159,14 @@ void us_encoder_open(us_encoder_s *enc, us_device_s *dev) {
US_MUTEX_UNLOCK(_ER(mutex));
const long double desired_interval = (
dev->desired_fps > 0 && (dev->desired_fps < dev->run->hw_fps || dev->run->hw_fps == 0)
? (long double)1 / dev->desired_fps
cap->desired_fps > 0 && (cap->desired_fps < cap->run->hw_fps || cap->run->hw_fps == 0)
? (long double)1 / cap->desired_fps
: 0
);
enc->run->pool = us_workers_pool_init(
"JPEG", "jw", n_workers, desired_interval,
_worker_job_init, (void *)enc,
_worker_job_init, (void*)enc,
_worker_job_destroy,
_worker_run_job);
@@ -188,19 +188,19 @@ void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, u
static void *_worker_job_init(void *v_enc) {
us_encoder_job_s *job;
US_CALLOC(job, 1);
job->enc = (us_encoder_s *)v_enc;
job->enc = (us_encoder_s*)v_enc;
job->dest = us_frame_init();
return (void *)job;
return (void*)job;
}
static void _worker_job_destroy(void *v_job) {
us_encoder_job_s *job = (us_encoder_job_s *)v_job;
us_encoder_job_s *job = v_job;
us_frame_destroy(job->dest);
free(job);
}
static bool _worker_run_job(us_worker_s *wr) {
us_encoder_job_s *job = (us_encoder_job_s *)wr->job;
us_encoder_job_s *job = wr->job;
us_encoder_s *enc = job->enc; // Just for _ER()
const us_frame_s *src = &job->hw->raw;
us_frame_s *dest = job->dest;

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -35,7 +35,7 @@
#include "../libs/threading.h"
#include "../libs/logging.h"
#include "../libs/frame.h"
#include "../libs/device.h"
#include "../libs/capture.h"
#include "workers.h"
#include "m2m.h"
@@ -75,9 +75,9 @@ typedef struct {
} us_encoder_s;
typedef struct {
us_encoder_s *enc;
us_hw_buffer_s *hw;
us_frame_s *dest;
us_encoder_s *enc;
us_capture_hwbuf_s *hw;
us_frame_s *dest;
} us_encoder_job_s;
@@ -87,7 +87,7 @@ void us_encoder_destroy(us_encoder_s *enc);
int us_encoder_parse_type(const char *str);
const char *us_encoder_type_to_string(us_encoder_type_e type);
void us_encoder_open(us_encoder_s *enc, us_device_s *dev);
void us_encoder_open(us_encoder_s *enc, us_capture_s *cap);
void us_encoder_close(us_encoder_s *enc);
void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, unsigned *quality);

View File

@@ -7,7 +7,7 @@
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
# Copyright (C) 2006 Gabriel A. Devenyi #
# Copyright (C) 2007 Tom Stöveken #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #
@@ -29,8 +29,8 @@
typedef struct {
struct jpeg_destination_mgr mgr; // Default manager
JOCTET *buf; // Start of buffer
struct jpeg_destination_mgr mgr; // Default manager
JOCTET *buf; // Start of buffer
us_frame_s *frame;
} _jpeg_dest_manager_s;
@@ -63,7 +63,12 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
jpeg.image_width = src->width;
jpeg.image_height = src->height;
jpeg.input_components = 3;
jpeg.in_color_space = ((src->format == V4L2_PIX_FMT_YUYV || src->format == V4L2_PIX_FMT_UYVY) ? JCS_YCbCr : JCS_RGB);
switch (src->format) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY: jpeg.in_color_space = JCS_YCbCr; break;
default: jpeg.in_color_space = JCS_RGB; break;
}
jpeg_set_defaults(&jpeg);
jpeg_set_quality(&jpeg, quality, TRUE);
@@ -89,12 +94,12 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame) {
if (jpeg->dest == NULL) {
assert((jpeg->dest = (struct jpeg_destination_mgr *)(*jpeg->mem->alloc_small)(
assert((jpeg->dest = (struct jpeg_destination_mgr*)(*jpeg->mem->alloc_small)(
(j_common_ptr) jpeg, JPOOL_PERMANENT, sizeof(_jpeg_dest_manager_s)
)) != NULL);
}
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
dest->mgr.init_destination = _jpeg_init_destination;
dest->mgr.empty_output_buffer = _jpeg_empty_output_buffer;
dest->mgr.term_destination = _jpeg_term_destination;
@@ -221,10 +226,10 @@ static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const
#define JPEG_OUTPUT_BUFFER_SIZE ((size_t)4096)
static void _jpeg_init_destination(j_compress_ptr jpeg) {
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
// Allocate the output buffer - it will be released when done with image
assert((dest->buf = (JOCTET *)(*jpeg->mem->alloc_small)(
assert((dest->buf = (JOCTET*)(*jpeg->mem->alloc_small)(
(j_common_ptr) jpeg, JPOOL_IMAGE, JPEG_OUTPUT_BUFFER_SIZE * sizeof(JOCTET)
)) != NULL);
@@ -235,7 +240,7 @@ static void _jpeg_init_destination(j_compress_ptr jpeg) {
static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg) {
// Called whenever local jpeg buffer fills up
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
us_frame_append_data(dest->frame, dest->buf, JPEG_OUTPUT_BUFFER_SIZE);
@@ -249,7 +254,7 @@ static void _jpeg_term_destination(j_compress_ptr jpeg) {
// Called by jpeg_finish_compress after all data has been written.
// Usually needs to flush buffer.
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s *)jpeg->dest;
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
const size_t final = JPEG_OUTPUT_BUFFER_SIZE - dest->mgr.free_in_buffer;
// Write any data remaining in the buffer.

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -7,7 +7,7 @@
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
# Copyright (C) 2006 Gabriel A. Devenyi #
# Copyright (C) 2007 Tom Stöveken #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -7,7 +7,7 @@
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
# Copyright (C) 2006 Gabriel A. Devenyi #
# Copyright (C) 2007 Tom Stöveken #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

View File

@@ -2,7 +2,7 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2023 Maxim Devaev <mdevaev@gmail.com> #
# Copyright (C) 2018-2024 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 #

Some files were not shown because too many files have changed in this diff Show More