Compare commits

...

70 Commits
v6.5 ... v6.13

Author SHA1 Message Date
Maxim Devaev
de8cb85605 Bump version: 6.12 → 6.13 2024-08-16 07:07:54 +03:00
Maxim Devaev
000be92a0b lint fix 2024-08-16 07:04:21 +03:00
Maxim Devaev
f2779f7b44 check for pkg-config 2024-08-16 06:38:52 +03:00
yuri@FreeBSD
dcddfddf56 Fix crash on FreeBSD due to incorrect thr_self system call invocation (#285)
The correct signature is:
int thr_self(long *id);

It was called as thr_self() which caused memory corruption.
2024-08-16 06:38:07 +03:00
Randolf Richardson 張文道
793f24c48e Update README.md (#275)
Minor spelling correction
2024-05-29 12:59:48 +03:00
Maxim Devaev
25d87d5fa8 Bump version: 6.11 → 6.12 2024-05-16 00:13:24 +03:00
Maxim Devaev
e8a7fb32ac lint fixes 2024-05-16 00:10:53 +03:00
Maxim Devaev
9d5eb8bacb fixed edid path 2024-05-16 00:01:03 +03:00
Maxim Devaev
353e58d7ca fix 2024-05-16 00:00:10 +03:00
Fabrice Fontaine
6c24c9ea61 src/libs/types.h: include sys/types.h (#273)
Include sys/types.h to avoid the following uclibc build failure since
version 5.52 and
2d6716aa47:

In file included from libs/base64.h:25,
                 from libs/base64.c:23:
libs/types.h:30:9: error: unknown type name 'ssize_t'
   30 | typedef ssize_t sz;
      |         ^~~~~~~

Fixes:
 - http://autobuild.buildroot.org/results/24498049d7beb4afaaf9f9a0c2fc0bcd26a3ee04

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2024-05-15 20:56:49 +03:00
Maxim Devaev
dfeefe5a1c Bump version: 6.10 → 6.11 2024-04-05 19:31:57 +03:00
Maxim Devaev
aae090ab4e list: clean next pointer on append 2024-04-05 19:29:13 +03:00
Maxim Devaev
18038799f0 reworked pool logic 2024-04-05 19:21:42 +03:00
Maxim Devaev
fab4c47f17 list: clean prev/next pointers on remove 2024-04-05 17:48:26 +03:00
Maxim Devaev
c40b3ee225 refactoring 2024-04-04 23:25:06 +03:00
Maxim Devaev
fca69db680 us_workers_pool_wait() without side effect 2024-04-04 23:21:34 +03:00
Maxim Devaev
0d974a5faf refactoring 2024-04-04 19:37:03 +03:00
Maxim Devaev
1ed39790ba use JCS_EXT_BGR on libjpeg-turbo 2024-04-04 15:20:16 +03:00
Maxim Devaev
75a193f997 syntax fix 2024-04-04 03:58:45 +03:00
Maxim Devaev
65c652e624 encoder: removed cpu_forced logic 2024-04-04 03:44:20 +03:00
Maxim Devaev
ae2f270f50 refactoring 2024-04-04 02:36:28 +03:00
Maxim Devaev
0a639eabca deprecated noop jpeg encoder 2024-04-03 20:23:35 +03:00
Maxim Devaev
9ec59143dd Bump version: 6.9 → 6.10 2024-04-01 22:03:40 +03:00
Maxim Devaev
e059a21ef9 refactoring 2024-04-01 21:40:51 +03:00
Maxim Devaev
074ce86f67 using fps_meta instead of flags 2024-04-01 00:12:42 +03:00
Maxim Devaev
b8b67de5cf mutexless fpsi at all 2024-03-31 17:33:51 +03:00
Maxim Devaev
5f3198e72f sort of fps reset 2024-03-30 21:37:13 +02:00
Maxim Devaev
3a3889d02c fpsi: mutexless mode 2024-03-30 19:34:43 +02:00
Maxim Devaev
88203f9c53 fix 2024-03-30 19:05:59 +02:00
Maxim Devaev
24aca349a3 we don't need us_fpsi_reset() anymore 2024-03-30 19:05:15 +02:00
Maxim Devaev
a9e0cb49e9 h264 and drm statistics in http 2024-03-30 17:48:15 +02:00
Maxim Devaev
4ec3f11935 refactoring 2024-03-30 16:10:46 +02:00
Maxim Devaev
14e9d9f7af fps -> fpsi, store frame meta 2024-03-30 15:35:14 +02:00
Maxim Devaev
580ca68291 US_FRAME_META_DECLARE 2024-03-30 13:13:17 +02:00
Maxim Devaev
37f3f093dc simplified list declaration 2024-03-30 13:07:20 +02:00
Maxim Devaev
70fa6548fe common fps counter 2024-03-30 12:15:59 +02:00
Maxim Devaev
f8a703f166 refactoring 2024-03-29 22:58:07 +02:00
Maxim Devaev
3f69dd785f fix 2024-03-29 15:41:54 +02:00
Maxim Devaev
8e6c374acf refactoring 2024-03-29 15:36:43 +02:00
Maxim Devaev
caf9ed7bfe refactoring 2024-03-29 03:34:35 +02:00
Maxim Devaev
94b1224456 fix 2024-03-29 02:24:36 +02:00
Maxim Devaev
c8201df720 don't rebuild python module without necessary 2024-03-29 01:15:02 +02:00
Maxim Devaev
e0f09f65a1 new macro US_ONCE_FOR() 2024-03-29 01:02:40 +02:00
Maxim Devaev
4e1f62bfac refactoring 2024-03-29 00:13:08 +02:00
Maxim Devaev
b0b881f199 fix 2024-03-28 18:38:01 +02:00
Maxim Devaev
a21f527bce common error constants 2024-03-28 17:17:22 +02:00
Maxim Devaev
d64077c2d5 Bump version: 6.8 → 6.9 2024-03-27 21:39:03 +02:00
Maxim Devaev
83f12baa61 refactoring 2024-03-27 19:27:28 +02:00
Maxim Devaev
b6fac2608d ustreamer-v4p: bring back busy message 2024-03-27 19:22:21 +02:00
Maxim Devaev
e6ebc12505 replaced comment 2024-03-27 02:14:36 +02:00
Maxim Devaev
8c92ab6f47 ustreamer: blank drm output by timeout 2024-03-26 22:20:08 +02:00
Maxim Devaev
7dc492d875 refactoring 2024-03-26 21:51:47 +02:00
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
126 changed files with 1758 additions and 1565 deletions

View File

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

3
.gitignore vendored
View File

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

View File

@@ -9,11 +9,19 @@ PY ?= python3
CFLAGS ?= -O3 CFLAGS ?= -O3
LDFLAGS ?= LDFLAGS ?=
R_DESTDIR = $(if $(DESTDIR),$(shell realpath "$(DESTDIR)"),)
export export
_LINTERS_IMAGE ?= ustreamer-linters _LINTERS_IMAGE ?= ustreamer-linters
# =====
ifeq (, $(shell which pkg-config))
$(error "No pkg-config found in $(PATH)")
endif
# ===== # =====
define optbool define optbool
$(filter $(shell echo $(1) | tr A-Z a-z), yes on 1) $(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
@@ -43,7 +51,7 @@ apps:
python: python:
$(MAKE) -C python $(MAKE) -C python
$(ECHO) ln -sf python/build/lib.*/*.so . $(ECHO) ln -sf python/root/usr/lib/python*/site-packages/*.so .
janus: janus:
@@ -59,10 +67,10 @@ endif
ifneq ($(call optbool,$(WITH_JANUS)),) ifneq ($(call optbool,$(WITH_JANUS)),)
$(MAKE) -C janus install $(MAKE) -C janus install
endif endif
mkdir -p $(DESTDIR)$(MANPREFIX)/man1 mkdir -p $(R_DESTDIR)$(MANPREFIX)/man1
for man in $(shell ls man); do \ for man in $(shell ls man); do \
install -m644 man/$$man $(DESTDIR)$(MANPREFIX)/man1/$$man; \ install -m644 man/$$man $(R_DESTDIR)$(MANPREFIX)/man1/$$man; \
gzip -f $(DESTDIR)$(MANPREFIX)/man1/$$man; \ gzip -f $(R_DESTDIR)$(MANPREFIX)/man1/$$man; \
done done

View File

@@ -23,7 +23,7 @@
| Compatibility with mjpg-streamer's API | ✔ | :) | | Compatibility with mjpg-streamer's API | ✔ | :) |
Footnotes: Footnotes:
* ```1``` Long before µStreamer, I made a [patch](https://github.com/jacksonliam/mjpg-streamer/pull/164) to add DV-timings support to mjpg-streamer and to keep it from hanging up no device disconnection. Alas, the patch is far from perfect and I can't guarantee it will work every time - mjpg-streamer's source code is very complicated and its structure is hard to understand. With this in mind, along with needing multithreading and JPEG hardware acceleration in the future, I decided to make my own stream server from scratch instead of supporting legacy code. * ```1``` Long before µStreamer, I made a [patch](https://github.com/jacksonliam/mjpg-streamer/pull/164) to add DV-timings support to mjpg-streamer and to keep it from hanging up on device disconnection. Alas, the patch is far from perfect and I can't guarantee it will work every time - mjpg-streamer's source code is very complicated and its structure is hard to understand. With this in mind, along with needing multithreading and JPEG hardware acceleration in the future, I decided to make my own stream server from scratch instead of supporting legacy code.
* ```2``` This feature allows to cut down outgoing traffic several-fold when streaming HDMI, but it increases CPU usage a little bit. The idea is that HDMI is a fully digital interface and each captured frame can be identical to the previous one byte-wise. There's no need to stream the same image over the net several times a second. With the `--drop-same-frames=20` option enabled, µStreamer will drop all the matching frames (with a limit of 20 in a row). Each new frame is matched with the previous one first by length, then using ```memcmp()```. * ```2``` This feature allows to cut down outgoing traffic several-fold when streaming HDMI, but it increases CPU usage a little bit. The idea is that HDMI is a fully digital interface and each captured frame can be identical to the previous one byte-wise. There's no need to stream the same image over the net several times a second. With the `--drop-same-frames=20` option enabled, µStreamer will drop all the matching frames (with a limit of 20 in a row). Each new frame is matched with the previous one first by length, then using ```memcmp()```.
@@ -209,7 +209,7 @@ v4l2 utilities provide the tools to manage USB webcam setting and information. S
----- -----
# License # 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 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 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 PREFIX ?= /usr/local
CC ?= gcc CC ?= gcc
@@ -42,8 +42,8 @@ $(_BUILD)/%.o: %.c
install: $(_PLUGIN) install: $(_PLUGIN)
mkdir -p $(DESTDIR)$(PREFIX)/lib/ustreamer/janus mkdir -p $(R_DESTDIR)$(PREFIX)/lib/ustreamer/janus
install -m755 $(_PLUGIN) $(DESTDIR)$(PREFIX)/lib/ustreamer/janus/$(PLUGIN) install -m755 $(_PLUGIN) $(R_DESTDIR)$(PREFIX)/lib/ustreamer/janus/$(PLUGIN)
clean: clean:

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -32,6 +32,7 @@
#include <opus/opus.h> #include <opus/opus.h>
#include "uslibs/types.h" #include "uslibs/types.h"
#include "uslibs/errors.h"
#include "uslibs/tools.h" #include "uslibs/tools.h"
#include "uslibs/array.h" #include "uslibs/array.h"
#include "uslibs/ring.h" #include "uslibs/ring.h"
@@ -185,12 +186,12 @@ int us_audio_get_encoded(us_audio_s *audio, u8 *data, uz *size, u64 *pts) {
} }
const int ri = us_ring_consumer_acquire(audio->enc_ring, 0.1); const int ri = us_ring_consumer_acquire(audio->enc_ring, 0.1);
if (ri < 0) { if (ri < 0) {
return -2; return US_ERROR_NO_DATA;
} }
const _enc_buffer_s *const buf = audio->enc_ring->items[ri]; const _enc_buffer_s *const buf = audio->enc_ring->items[ri];
if (*size < buf->used) { if (*size < buf->used) {
us_ring_consumer_release(audio->enc_ring, ri); us_ring_consumer_release(audio->enc_ring, ri);
return -3; return US_ERROR_NO_DATA;
} }
memcpy(data, buf->data, buf->used); memcpy(data, buf->data, buf->used);
*size = buf->used; *size = buf->used;

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -34,7 +34,7 @@
#include "rtp.h" #include "rtp.h"
typedef struct us_janus_client_sx { typedef struct {
janus_callbacks *gw; janus_callbacks *gw;
janus_plugin_session *session; janus_plugin_session *session;
atomic_bool transmit; atomic_bool transmit;
@@ -48,7 +48,7 @@ typedef struct us_janus_client_sx {
us_ring_s *video_ring; us_ring_s *video_ring;
us_ring_s *audio_ring; us_ring_s *audio_ring;
US_LIST_STRUCT(struct us_janus_client_sx); US_LIST_DECLARE;
} us_janus_client_s; } us_janus_client_s;

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -27,6 +27,7 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include "uslibs/types.h" #include "uslibs/types.h"
#include "uslibs/errors.h"
#include "uslibs/tools.h" #include "uslibs/tools.h"
#include "uslibs/frame.h" #include "uslibs/frame.h"
#include "uslibs/memsinksh.h" #include "uslibs/memsinksh.h"
@@ -54,7 +55,7 @@ int us_memsink_fd_wait_frame(int fd, us_memsink_shared_s *mem, u64 last_id) {
} }
usleep(1000); // lock_polling usleep(1000); // lock_polling
} while (now_ts < deadline_ts); } while (now_ts < deadline_ts);
return -2; return US_ERROR_NO_DATA;
} }
int us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, us_frame_s *frame, u64 *frame_id, bool key_required) { int us_memsink_fd_get_frame(int fd, us_memsink_shared_s *mem, us_frame_s *frame, u64 *frame_id, bool key_required) {

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -37,6 +37,7 @@
#include "uslibs/types.h" #include "uslibs/types.h"
#include "uslibs/const.h" #include "uslibs/const.h"
#include "uslibs/errors.h"
#include "uslibs/tools.h" #include "uslibs/tools.h"
#include "uslibs/threading.h" #include "uslibs/threading.h"
#include "uslibs/list.h" #include "uslibs/list.h"
@@ -178,7 +179,7 @@ static void *_video_sink_thread(void *arg) {
if (ri >= 0 && frame->key) { if (ri >= 0 && frame->key) {
atomic_store(&_g_key_required, false); atomic_store(&_g_key_required, false);
} }
} else if (waited != -2) { } else if (waited != US_ERROR_NO_DATA) {
goto close_memsink; goto close_memsink;
} }
} }

View File

@@ -5,7 +5,7 @@
# This source file is partially based on this code: # # This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src # # - 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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: # # This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src # # - 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #

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

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

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

@@ -3,7 +3,7 @@ envlist = cppcheck, flake8, pylint, mypy, vulture, htmlhint
skipsdist = true skipsdist = true
[testenv] [testenv]
basepython = python3.11 basepython = python3.12
changedir = /src changedir = /src
[testenv:cppcheck] [testenv:cppcheck]
@@ -13,6 +13,7 @@ commands = cppcheck \
--std=c17 \ --std=c17 \
--error-exitcode=1 \ --error-exitcode=1 \
--quiet \ --quiet \
--check-level=exhaustive \
--enable=warning,portability,performance,style \ --enable=warning,portability,performance,style \
--suppress=assignmentInAssert \ --suppress=assignmentInAssert \
--suppress=variableScope \ --suppress=variableScope \
@@ -25,7 +26,7 @@ commands = cppcheck \
allowlist_externals = bash allowlist_externals = bash
commands = bash -c 'flake8 --config=linters/flake8.ini tools/*.py' python/*.py commands = bash -c 'flake8 --config=linters/flake8.ini tools/*.py' python/*.py
deps = deps =
flake8==5.0.4 flake8
flake8-quotes flake8-quotes
[testenv:pylint] [testenv:pylint]
@@ -33,6 +34,7 @@ allowlist_externals = bash
commands = bash -c 'pylint --rcfile=linters/pylint.ini --output-format=colorized --reports=no tools/*.py python/*.py' commands = bash -c 'pylint --rcfile=linters/pylint.ini --output-format=colorized --reports=no tools/*.py python/*.py'
deps = deps =
pylint pylint
setuptools
[testenv:mypy] [testenv:mypy]
allowlist_externals = bash allowlist_externals = bash

View File

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

View File

@@ -1,6 +1,6 @@
.\" Manpage for ustreamer. .\" Manpage for ustreamer.
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos .\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
.TH USTREAMER 1 "version 6.5" "November 2020" .TH USTREAMER 1 "version 6.13" "November 2020"
.SH NAME .SH NAME
ustreamer \- stream MJPEG video from any V4L2 device to the network ustreamer \- stream MJPEG video from any V4L2 device to the network
@@ -96,8 +96,6 @@ HW ─ Use pre-encoded MJPEG frames directly from camera hardware.
M2M-VIDEO ─ GPU-accelerated MJPEG encoding. M2M-VIDEO ─ GPU-accelerated MJPEG encoding.
M2M-IMAGE ─ GPU-accelerated JPEG encoding. M2M-IMAGE ─ GPU-accelerated JPEG encoding.
NOOP ─ Don't compress MJPEG stream (do nothing).
.TP .TP
.BR \-g\ \fIWxH,... ", " \-\-glitched\-resolutions\ \fIWxH,... .BR \-g\ \fIWxH,... ", " \-\-glitched\-resolutions\ \fIWxH,...
It doesn't do anything. Still here for compatibility. It doesn't do anything. Still here for compatibility.

View File

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

View File

@@ -24,7 +24,7 @@ RUN apk add --no-cache \
WORKDIR /ustreamer WORKDIR /ustreamer
COPY --from=build /build/ustreamer/src/ustreamer.bin ustreamer COPY --from=build /build/ustreamer/src/ustreamer.bin ustreamer
RUN wget https://raw.githubusercontent.com/pikvm/kvmd/master/configs/kvmd/edid/v3-hdmi.hex -O /edid.hex RUN wget https://raw.githubusercontent.com/pikvm/kvmd/master/configs/kvmd/edid/v2.hex -O /edid.hex
COPY pkg/docker/entry.sh / COPY pkg/docker/entry.sh /
EXPOSE 8080 EXPOSE 8080

View File

@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=ustreamer PKG_NAME:=ustreamer
PKG_VERSION:=6.5 PKG_VERSION:=6.13
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com> 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,20 +1,23 @@
-include ../config.mk -include ../config.mk
DESTDIR ?= R_DESTDIR ?=
PREFIX ?= /usr/local PREFIX ?= /usr/local
PY ?= python3 PY ?= python3
# ===== # =====
all: all: root
root: $(shell find src -type f,l)
$(info == PY_BUILD ustreamer-*.so) $(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: 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: 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__": if __name__ == "__main__":
setup( setup(
name="ustreamer", name="ustreamer",
version="6.5", version="6.13",
description="uStreamer tools", description="uStreamer tools",
author="Maxim Devaev", author="Maxim Devaev",
author_email="mdevaev@gmail.com", author_email="mdevaev@gmail.com",
@@ -29,7 +29,6 @@ if __name__ == "__main__":
extra_compile_args=["-std=c17", "-D_GNU_SOURCE"], extra_compile_args=["-std=c17", "-D_GNU_SOURCE"],
undef_macros=["NDEBUG"], undef_macros=["NDEBUG"],
sources=_find_sources(".c"), sources=_find_sources(".c"),
depends=_find_sources(".h"),
), ),
], ],
) )

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

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

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

@@ -14,6 +14,7 @@
#include <Python.h> #include <Python.h>
#include "uslibs/types.h" #include "uslibs/types.h"
#include "uslibs/errors.h"
#include "uslibs/tools.h" #include "uslibs/tools.h"
#include "uslibs/frame.h" #include "uslibs/frame.h"
#include "uslibs/memsinksh.h" #include "uslibs/memsinksh.h"
@@ -175,9 +176,9 @@ static int _wait_frame(_MemsinkObject *self) {
if (PyErr_CheckSignals() < 0) { if (PyErr_CheckSignals() < 0) {
return -1; return -1;
} }
} while (now_ts < deadline_ts); } while (now_ts < deadline_ts);
return -2;
return US_ERROR_NO_DATA;
} }
static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, PyObject *kwargs) { static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args, PyObject *kwargs) {
@@ -194,7 +195,7 @@ static PyObject *_MemsinkObject_wait_frame(_MemsinkObject *self, PyObject *args,
switch (_wait_frame(self)) { switch (_wait_frame(self)) {
case 0: break; case 0: break;
case -2: Py_RETURN_NONE; case US_ERROR_NO_DATA: Py_RETURN_NONE;
default: return NULL; default: return NULL;
} }

View File

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

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -31,10 +31,12 @@
#include <assert.h> #include <assert.h>
#include "../libs/const.h" #include "../libs/const.h"
#include "../libs/errors.h"
#include "../libs/tools.h" #include "../libs/tools.h"
#include "../libs/logging.h" #include "../libs/logging.h"
#include "../libs/frame.h" #include "../libs/frame.h"
#include "../libs/memsink.h" #include "../libs/memsink.h"
#include "../libs/fpsi.h"
#include "../libs/signal.h" #include "../libs/signal.h"
#include "../libs/options.h" #include "../libs/options.h"
@@ -109,9 +111,9 @@ int main(int argc, char *argv[]) {
US_LOGGING_INIT; US_LOGGING_INIT;
US_THREAD_RENAME("main"); US_THREAD_RENAME("main");
char *sink_name = NULL; const char *sink_name = NULL;
unsigned sink_timeout = 1; unsigned sink_timeout = 1;
char *output_path = NULL; const char *output_path = NULL;
bool output_json = false; bool output_json = false;
long long count = 0; long long count = 0;
long double interval = 0; long double interval = 0;
@@ -220,26 +222,22 @@ static int _dump_sink(
const useconds_t interval_us = interval * 1000000; const useconds_t interval_us = interval * 1000000;
us_frame_s *frame = us_frame_init(); us_frame_s *frame = us_frame_init();
us_fpsi_s *fpsi = us_fpsi_init("SINK", false);
us_memsink_s *sink = NULL; us_memsink_s *sink = NULL;
if ((sink = us_memsink_init("input", sink_name, false, 0, false, 0, sink_timeout)) == NULL) { if ((sink = us_memsink_init_opened("input", sink_name, false, 0, false, 0, sink_timeout)) == NULL) {
goto error; goto error;
} }
unsigned fps = 0;
unsigned fps_accum = 0;
long long fps_second = 0;
long double last_ts = 0; long double last_ts = 0;
while (!_g_stop) { while (!_g_stop) {
bool key_requested; bool key_requested;
const int error = us_memsink_client_get(sink, frame, &key_requested, key_required); const int got = us_memsink_client_get(sink, frame, &key_requested, key_required);
if (error == 0) { if (got == 0) {
key_required = false; key_required = false;
const long double now = us_get_now_monotonic(); const long double now = us_get_now_monotonic();
const long long now_second = us_floor_ms(now);
char fourcc_str[8]; char fourcc_str[8];
US_LOG_VERBOSE("Frame: %s - %ux%u -- online=%d, key=%d, kr=%d, gop=%u, latency=%.3Lf, backlog=%.3Lf, size=%zu", US_LOG_VERBOSE("Frame: %s - %ux%u -- online=%d, key=%d, kr=%d, gop=%u, latency=%.3Lf, backlog=%.3Lf, size=%zu",
@@ -253,13 +251,7 @@ static int _dump_sink(
US_LOG_DEBUG(" stride=%u, grab_ts=%.3Lf, encode_begin_ts=%.3Lf, encode_end_ts=%.3Lf", US_LOG_DEBUG(" stride=%u, grab_ts=%.3Lf, encode_begin_ts=%.3Lf, encode_end_ts=%.3Lf",
frame->stride, frame->grab_ts, frame->encode_begin_ts, frame->encode_end_ts); frame->stride, frame->grab_ts, frame->encode_begin_ts, frame->encode_end_ts);
if (now_second != fps_second) { us_fpsi_update(fpsi, true, NULL);
fps = fps_accum;
fps_accum = 0;
fps_second = now_second;
US_LOG_PERF_FPS("A new second has come; captured_fps=%u", fps);
}
fps_accum += 1;
if (ctx->v_output != NULL) { if (ctx->v_output != NULL) {
ctx->write(ctx->v_output, frame); ctx->write(ctx->v_output, frame);
@@ -275,7 +267,7 @@ static int _dump_sink(
if (interval_us > 0) { if (interval_us > 0) {
usleep(interval_us); usleep(interval_us);
} }
} else if (error == -2) { } else if (got == US_ERROR_NO_DATA) {
usleep(1000); usleep(1000);
} else { } else {
goto error; goto error;
@@ -286,6 +278,7 @@ static int _dump_sink(
error: error:
US_DELETE(sink, us_memsink_destroy); US_DELETE(sink, us_memsink_destroy);
us_fpsi_destroy(fpsi);
us_frame_destroy(frame); us_frame_destroy(frame);
US_LOG_INFO("Bye-bye"); US_LOG_INFO("Bye-bye");
return retval; return retval;
@@ -296,7 +289,7 @@ static void _help(FILE *fp) {
SAY("\nuStreamer-dump - Dump uStreamer's memory sink to file"); SAY("\nuStreamer-dump - Dump uStreamer's memory sink to file");
SAY("═════════════════════════════════════════════════════"); SAY("═════════════════════════════════════════════════════");
SAY("Version: %s; license: GPLv3", US_VERSION); 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("Example:");
SAY("════════"); SAY("════════");
SAY(" ustreamer-dump --sink test --output - \\"); SAY(" ustreamer-dump --sink test --output - \\");

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -49,7 +49,7 @@ typedef struct {
int dma_fd; int dma_fd;
bool grabbed; bool grabbed;
atomic_int refs; atomic_int refs;
} us_hw_buffer_s; } us_capture_hwbuf_s;
typedef struct { typedef struct {
int fd; int fd;
@@ -62,13 +62,13 @@ typedef struct {
uint jpeg_quality; uint jpeg_quality;
uz raw_size; uz raw_size;
uint n_bufs; uint n_bufs;
us_hw_buffer_s *hw_bufs; us_capture_hwbuf_s *bufs;
bool dma; bool dma;
enum v4l2_buf_type capture_type; enum v4l2_buf_type capture_type;
bool capture_mplane; bool capture_mplane;
bool streamon; bool streamon;
int open_error_reported; int open_error_once;
} us_device_runtime_s; } us_capture_runtime_s;
typedef enum { typedef enum {
CTL_MODE_NONE = 0, CTL_MODE_NONE = 0,
@@ -104,6 +104,8 @@ typedef struct {
uint width; uint width;
uint height; uint height;
uint format; uint format;
bool format_swap_rgb;
uint jpeg_quality; uint jpeg_quality;
v4l2_std_id standard; v4l2_std_id standard;
enum v4l2_memory io_method; enum v4l2_memory io_method;
@@ -116,22 +118,22 @@ typedef struct {
bool persistent; bool persistent;
uint timeout; uint timeout;
us_controls_s ctl; us_controls_s ctl;
us_device_runtime_s *run; us_capture_runtime_s *run;
} us_device_s; } us_capture_s;
us_device_s *us_device_init(void); us_capture_s *us_capture_init(void);
void us_device_destroy(us_device_s *dev); void us_capture_destroy(us_capture_s *cap);
int us_device_parse_format(const char *str); int us_capture_parse_format(const char *str);
int us_device_parse_standard(const char *str); int us_capture_parse_standard(const char *str);
int us_device_parse_io_method(const char *str); int us_capture_parse_io_method(const char *str);
int us_device_open(us_device_s *dev); int us_capture_open(us_capture_s *cap);
void us_device_close(us_device_s *dev); void us_capture_close(us_capture_s *cap);
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw); int us_capture_hwbuf_grab(us_capture_s *cap, us_capture_hwbuf_s **hw);
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw); int us_capture_hwbuf_release(const us_capture_s *cap, us_capture_hwbuf_s *hw);
void us_device_buffer_incref(us_hw_buffer_s *hw); void us_capture_hwbuf_incref(us_capture_hwbuf_s *hw);
void us_device_buffer_decref(us_hw_buffer_s *hw); void us_capture_hwbuf_decref(us_capture_hwbuf_s *hw);

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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_MAJOR 6
#define US_VERSION_MINOR 5 #define US_VERSION_MINOR 13
#define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor #define US_MAKE_VERSION2(_major, _minor) #_major "." #_minor
#define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor) #define US_MAKE_VERSION1(_major, _minor) US_MAKE_VERSION2(_major, _minor)

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -37,17 +37,19 @@
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <libdrm/drm.h> #include <libdrm/drm.h>
#include "../libs/types.h" #include "../types.h"
#include "../libs/tools.h" #include "../errors.h"
#include "../libs/logging.h" #include "../tools.h"
#include "../libs/frame.h" #include "../logging.h"
#include "../libs/frametext.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 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 int _drm_check_status(us_drm_s *drm);
static void _drm_ensure_dpms_power(us_drm_s *drm, bool on); 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 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); static drmModeModeInfo *_find_best_mode(drmModeConnector *conn, uint width, uint height, float hz);
@@ -57,11 +59,11 @@ static const char *_connector_type_to_string(u32 type);
static float _get_refresh_rate(const drmModeModeInfo *mode); static float _get_refresh_rate(const drmModeModeInfo *mode);
#define _D_LOG_ERROR(x_msg, ...) US_LOG_ERROR("DRM: " x_msg, ##__VA_ARGS__) #define _LOG_ERROR(x_msg, ...) US_LOG_ERROR("DRM: " x_msg, ##__VA_ARGS__)
#define _D_LOG_PERROR(x_msg, ...) US_LOG_PERROR("DRM: " x_msg, ##__VA_ARGS__) #define _LOG_PERROR(x_msg, ...) US_LOG_PERROR("DRM: " x_msg, ##__VA_ARGS__)
#define _D_LOG_INFO(x_msg, ...) US_LOG_INFO("DRM: " x_msg, ##__VA_ARGS__) #define _LOG_INFO(x_msg, ...) US_LOG_INFO("DRM: " x_msg, ##__VA_ARGS__)
#define _D_LOG_VERBOSE(x_msg, ...) US_LOG_VERBOSE("DRM: " x_msg, ##__VA_ARGS__) #define _LOG_VERBOSE(x_msg, ...) US_LOG_VERBOSE("DRM: " x_msg, ##__VA_ARGS__)
#define _D_LOG_DEBUG(x_msg, ...) US_LOG_DEBUG("DRM: " x_msg, ##__VA_ARGS__) #define _LOG_DEBUG(x_msg, ...) US_LOG_DEBUG("DRM: " x_msg, ##__VA_ARGS__)
us_drm_s *us_drm_init(void) { us_drm_s *us_drm_init(void) {
@@ -70,6 +72,7 @@ us_drm_s *us_drm_init(void) {
run->fd = -1; run->fd = -1;
run->status_fd = -1; run->status_fd = -1;
run->dpms_state = -1; run->dpms_state = -1;
run->opened = -1;
run->has_vsync = true; run->has_vsync = true;
run->exposing_dma_fd = -1; run->exposing_dma_fd = -1;
run->ft = us_frametext_init(); run->ft = us_frametext_init();
@@ -78,8 +81,9 @@ us_drm_s *us_drm_init(void) {
US_CALLOC(drm, 1); US_CALLOC(drm, 1);
// drm->path = "/dev/dri/card0"; // drm->path = "/dev/dri/card0";
drm->path = "/dev/dri/by-path/platform-gpu-card"; 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->timeout = 5;
drm->blank_after = 5;
drm->run = run; drm->run = run;
return drm; return drm;
} }
@@ -90,44 +94,45 @@ void us_drm_destroy(us_drm_s *drm) {
US_DELETE(drm, free); // cppcheck-suppress uselessAssignmentPtrArg 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; us_drm_runtime_s *const run = drm->run;
assert(run->fd < 0); assert(run->fd < 0);
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
case -2: goto unplugged; case US_ERROR_NO_DEVICE: goto unplugged;
default: goto error; default: goto error;
} }
_D_LOG_INFO("Configuring DRM device for %s ...", (dev == NULL ? "STUB" : "DMA")); _LOG_INFO("Using passthrough: %s[%s]", drm->path, drm->port);
_LOG_INFO("Configuring DRM device for %s ...", (cap == NULL ? "STUB" : "DMA"));
if ((run->fd = open(drm->path, O_RDWR | O_CLOEXEC | O_NONBLOCK)) < 0) { if ((run->fd = open(drm->path, O_RDWR | O_CLOEXEC | O_NONBLOCK)) < 0) {
_D_LOG_PERROR("Can't open DRM device"); _LOG_PERROR("Can't open DRM device");
goto error; goto error;
} }
_D_LOG_DEBUG("DRM device fd=%d opened", run->fd); _LOG_DEBUG("DRM device fd=%d opened", run->fd);
int stub = 0; // Open the real device with DMA int stub = 0; // Open the real device with DMA
if (dev == NULL) { if (cap == NULL) {
stub = US_DRM_STUB_USER; 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; stub = US_DRM_STUB_BAD_FORMAT;
char fourcc_str[8]; 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); _LOG_ERROR("Input format %s is not supported, forcing to STUB ...", fourcc_str);
} }
# define CHECK_CAP(x_cap) { \ # define CHECK_CAP(x_cap) { \
_D_LOG_DEBUG("Checking %s ...", #x_cap); \ _LOG_DEBUG("Checking %s ...", #x_cap); \
u64 m_check; \ u64 m_check; \
if (drmGetCap(run->fd, x_cap, &m_check) < 0) { \ if (drmGetCap(run->fd, x_cap, &m_check) < 0) { \
_D_LOG_PERROR("Can't check " #x_cap); \ _LOG_PERROR("Can't check " #x_cap); \
goto error; \ goto error; \
} \ } \
if (!m_check) { \ if (!m_check) { \
_D_LOG_ERROR(#x_cap " is not supported"); \ _LOG_ERROR(#x_cap " is not supported"); \
goto error; \ goto error; \
} \ } \
} }
@@ -137,48 +142,49 @@ int us_drm_open(us_drm_s *drm, const us_device_s *dev) {
} }
# undef CHECK_CAP # undef CHECK_CAP
const uint width = (stub > 0 ? 0 : dev->run->width); const uint width = (stub > 0 ? 0 : cap->run->width);
const uint height = (stub > 0 ? 0 : dev->run->height); const uint height = (stub > 0 ? 0 : cap->run->height);
const uint hz = (stub > 0 ? 0 : dev->run->hz); const uint hz = (stub > 0 ? 0 : cap->run->hz);
switch (_drm_find_sink(drm, width, height, hz)) { switch (_drm_find_sink(drm, width, height, hz)) {
case 0: break; case 0: break;
case -2: goto unplugged; case US_ERROR_NO_DEVICE: goto unplugged;
default: goto error; default: goto error;
} }
if ((stub == 0) && (width != run->mode.hdisplay || height < run->mode.vdisplay)) { if ((stub == 0) && (width != run->mode.hdisplay || height < run->mode.vdisplay)) {
// We'll try to show something instead of nothing if height != vdisplay // We'll try to show something instead of nothing if height != vdisplay
stub = US_DRM_STUB_BAD_RESOLUTION; stub = US_DRM_STUB_BAD_RESOLUTION;
_D_LOG_ERROR("There is no appropriate modes for the capture, forcing to STUB ..."); _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; goto error;
} }
run->saved_crtc = drmModeGetCrtc(run->fd, run->crtc_id); run->saved_crtc = drmModeGetCrtc(run->fd, run->crtc_id);
_D_LOG_DEBUG("Setting up CRTC ..."); _LOG_DEBUG("Setting up CRTC ...");
if (drmModeSetCrtc(run->fd, run->crtc_id, run->bufs[0].id, 0, 0, &run->conn_id, 1, &run->mode) < 0) { if (drmModeSetCrtc(run->fd, run->crtc_id, run->bufs[0].id, 0, 0, &run->conn_id, 1, &run->mode) < 0) {
_D_LOG_PERROR("Can't set CRTC"); _LOG_PERROR("Can't set CRTC");
goto error; goto error;
} }
run->opened_for_stub = (stub > 0); _LOG_INFO("Opened for %s ...", (stub > 0 ? "STUB" : "DMA"));
run->exposing_dma_fd = -1; run->exposing_dma_fd = -1;
run->unplugged_reported = false; run->blank_at_ts = 0;
_D_LOG_INFO("Opened for %s ...", (run->opened_for_stub ? "STUB" : "DMA")); run->opened = stub;
return stub; run->once = 0;
return run->opened;
error: error:
us_drm_close(drm); us_drm_close(drm);
return -1; return run->opened; // -1 after us_drm_close()
unplugged: unplugged:
if (!run->unplugged_reported) { US_ONCE_FOR(run->once, __LINE__, {
_D_LOG_ERROR("Display is not plugged"); _LOG_ERROR("Display is not plugged");
run->unplugged_reported = true; });
}
us_drm_close(drm); us_drm_close(drm);
return -2; run->opened = US_ERROR_NO_DEVICE;
return run->opened;
} }
void us_drm_close(us_drm_s *drm) { void us_drm_close(us_drm_s *drm) {
@@ -193,33 +199,33 @@ void us_drm_close(us_drm_s *drm) {
} }
if (run->saved_crtc != NULL) { if (run->saved_crtc != NULL) {
_D_LOG_DEBUG("Restoring CRTC ..."); _LOG_DEBUG("Restoring CRTC ...");
if (drmModeSetCrtc(run->fd, if (drmModeSetCrtc(run->fd,
run->saved_crtc->crtc_id, run->saved_crtc->buffer_id, run->saved_crtc->crtc_id, run->saved_crtc->buffer_id,
run->saved_crtc->x, run->saved_crtc->y, run->saved_crtc->x, run->saved_crtc->y,
&run->conn_id, 1, &run->saved_crtc->mode &run->conn_id, 1, &run->saved_crtc->mode
) < 0 && errno != ENOENT) { ) < 0 && errno != ENOENT) {
_D_LOG_PERROR("Can't restore CRTC"); _LOG_PERROR("Can't restore CRTC");
} }
drmModeFreeCrtc(run->saved_crtc); drmModeFreeCrtc(run->saved_crtc);
run->saved_crtc = NULL; run->saved_crtc = NULL;
} }
if (run->bufs != NULL) { if (run->bufs != NULL) {
_D_LOG_DEBUG("Releasing buffers ..."); _LOG_DEBUG("Releasing buffers ...");
for (uint n_buf = 0; n_buf < run->n_bufs; ++n_buf) { for (uint n_buf = 0; n_buf < run->n_bufs; ++n_buf) {
us_drm_buffer_s *const buf = &run->bufs[n_buf]; us_drm_buffer_s *const buf = &run->bufs[n_buf];
if (buf->fb_added && drmModeRmFB(run->fd, buf->id) < 0) { if (buf->fb_added && drmModeRmFB(run->fd, buf->id) < 0) {
_D_LOG_PERROR("Can't remove buffer=%u", n_buf); _LOG_PERROR("Can't remove buffer=%u", n_buf);
} }
if (buf->dumb_created) { if (buf->dumb_created) {
struct drm_mode_destroy_dumb destroy = {.handle = buf->handle}; struct drm_mode_destroy_dumb destroy = {.handle = buf->handle};
if (drmIoctl(run->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy) < 0) { if (drmIoctl(run->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy) < 0) {
_D_LOG_PERROR("Can't destroy dumb buffer=%u", n_buf); _LOG_PERROR("Can't destroy dumb buffer=%u", n_buf);
} }
} }
if (buf->data != NULL && munmap(buf->data, buf->allocated)) { if (buf->data != NULL && munmap(buf->data, buf->allocated)) {
_D_LOG_PERROR("Can't unmap buffer=%u", n_buf); _LOG_PERROR("Can't unmap buffer=%u", n_buf);
} }
} }
US_DELETE(run->bufs, free); US_DELETE(run->bufs, free);
@@ -232,19 +238,48 @@ void us_drm_close(us_drm_s *drm) {
run->crtc_id = 0; run->crtc_id = 0;
run->dpms_state = -1; run->dpms_state = -1;
run->opened = -1;
run->has_vsync = true; run->has_vsync = true;
run->stub_n_buf = 0; run->stub_n_buf = 0;
if (say) { if (say) {
_D_LOG_INFO("Closed"); _LOG_INFO("Closed");
} }
} }
int us_drm_ensure_no_signal(us_drm_s *drm) {
us_drm_runtime_s *const run = drm->run;
assert(run->fd >= 0);
assert(run->opened > 0);
const ldf now_ts = us_get_now_monotonic();
if (run->blank_at_ts == 0) {
run->blank_at_ts = now_ts + drm->blank_after;
}
const ldf saved_ts = run->blank_at_ts; // us_drm*() rewrites it to 0
int retval;
if (now_ts <= run->blank_at_ts) {
retval = us_drm_wait_for_vsync(drm);
if (retval == 0) {
retval = us_drm_expose_stub(drm, US_DRM_STUB_NO_SIGNAL, NULL);
}
} else {
US_ONCE_FOR(run->once, __LINE__, {
_LOG_INFO("Turning off the display by timeout ...");
});
retval = us_drm_dpms_power_off(drm);
}
run->blank_at_ts = saved_ts;
return retval;
}
int us_drm_dpms_power_off(us_drm_s *drm) { int us_drm_dpms_power_off(us_drm_s *drm) {
assert(drm->run->fd >= 0); assert(drm->run->fd >= 0);
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
case -2: return 0; // Unplugged, nice case US_ERROR_NO_DEVICE: return 0; // Unplugged, nice
// Во время переключения DPMS монитор моргает один раз состоянием disconnected, // Во время переключения DPMS монитор моргает один раз состоянием disconnected,
// а потом почему-то снова оказывается connected. Так что просто считаем, // а потом почему-то снова оказывается connected. Так что просто считаем,
// что отсоединенный монитор на этом этапе - это нормально. // что отсоединенный монитор на этом этапе - это нормально.
@@ -258,10 +293,11 @@ int us_drm_wait_for_vsync(us_drm_s *drm) {
us_drm_runtime_s *const run = drm->run; us_drm_runtime_s *const run = drm->run;
assert(run->fd >= 0); assert(run->fd >= 0);
run->blank_at_ts = 0;
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
case -2: return -2; case US_ERROR_NO_DEVICE: return US_ERROR_NO_DEVICE;
default: return -1; default: return -1;
} }
_drm_ensure_dpms_power(drm, true); _drm_ensure_dpms_power(drm, true);
@@ -275,13 +311,13 @@ int us_drm_wait_for_vsync(us_drm_s *drm) {
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(run->fd, &fds); FD_SET(run->fd, &fds);
_D_LOG_DEBUG("Calling select() for VSync ..."); _LOG_DEBUG("Calling select() for VSync ...");
const int result = select(run->fd + 1, &fds, NULL, NULL, &timeout); const int result = select(run->fd + 1, &fds, NULL, NULL, &timeout);
if (result < 0) { if (result < 0) {
_D_LOG_PERROR("Can't select(%d) device for VSync", run->fd); _LOG_PERROR("Can't select(%d) device for VSync", run->fd);
return -1; return -1;
} else if (result == 0) { } else if (result == 0) {
_D_LOG_ERROR("Device timeout while waiting VSync"); _LOG_ERROR("Device timeout while waiting VSync");
return -1; return -1;
} }
@@ -289,9 +325,9 @@ int us_drm_wait_for_vsync(us_drm_s *drm) {
.version = DRM_EVENT_CONTEXT_VERSION, .version = DRM_EVENT_CONTEXT_VERSION,
.page_flip_handler = _drm_vsync_callback, .page_flip_handler = _drm_vsync_callback,
}; };
_D_LOG_DEBUG("Handling DRM event (maybe VSync) ..."); _LOG_DEBUG("Handling DRM event (maybe VSync) ...");
if (drmHandleEvent(run->fd, &ctx) < 0) { if (drmHandleEvent(run->fd, &ctx) < 0) {
_D_LOG_PERROR("Can't handle DRM event"); _LOG_PERROR("Can't handle DRM event");
return -1; return -1;
} }
return 0; return 0;
@@ -305,18 +341,19 @@ static void _drm_vsync_callback(int fd, uint n_frame, uint sec, uint usec, void
us_drm_buffer_s *const buf = v_buf; us_drm_buffer_s *const buf = v_buf;
*buf->ctx.has_vsync = true; *buf->ctx.has_vsync = true;
*buf->ctx.exposing_dma_fd = -1; *buf->ctx.exposing_dma_fd = -1;
_D_LOG_DEBUG("Got VSync signal"); _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; us_drm_runtime_s *const run = drm->run;
assert(run->fd >= 0); assert(run->fd >= 0);
assert(run->opened_for_stub); assert(run->opened > 0);
run->blank_at_ts = 0;
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
case -2: return -2; case US_ERROR_NO_DEVICE: return US_ERROR_NO_DEVICE;
default: return -1; default: return -1;
} }
_drm_ensure_dpms_power(drm, true); _drm_ensure_dpms_power(drm, true);
@@ -324,24 +361,19 @@ 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) # define DRAW_MSG(x_msg) us_frametext_draw(run->ft, (x_msg), run->mode.hdisplay, run->mode.vdisplay)
switch (stub) { switch (stub) {
case US_DRM_STUB_BAD_RESOLUTION: { case US_DRM_STUB_BAD_RESOLUTION: {
assert(dev != NULL); assert(cap != NULL);
char msg[1024]; char msg[1024];
US_SNPRINTF(msg, 1023, US_SNPRINTF(msg, 1023,
"=== PiKVM ===" "=== PiKVM ==="
"\n \n< UNSUPPORTED RESOLUTION >" "\n \n< UNSUPPORTED RESOLUTION >"
"\n \n< %ux%up%.02f >" "\n \n< %ux%up%.02f >"
"\n \nby this display", "\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); DRAW_MSG(msg);
break; break;
}; };
case US_DRM_STUB_BAD_FORMAT: case US_DRM_STUB_BAD_FORMAT:
DRAW_MSG( DRAW_MSG("=== PiKVM ===\n \n< UNSUPPORTED CAPTURE FORMAT >");
"=== PiKVM ==="
"\n \n< UNSUPPORTED CAPTURE FORMAT >"
"\n \nIt shouldn't happen ever."
"\n \nPlease check the logs and report a bug:"
"\n \n- https://github.com/pikvm/pikvm -");
break; break;
case US_DRM_STUB_NO_SIGNAL: case US_DRM_STUB_NO_SIGNAL:
DRAW_MSG("=== PiKVM ===\n \n< NO SIGNAL >"); DRAW_MSG("=== PiKVM ===\n \n< NO SIGNAL >");
@@ -359,48 +391,49 @@ int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_device_s *dev
run->has_vsync = false; run->has_vsync = false;
_D_LOG_DEBUG("Copying STUB frame ...") _LOG_DEBUG("Copying STUB frame ...")
memcpy(buf->data, run->ft->frame->data, US_MIN(run->ft->frame->used, buf->allocated)); memcpy(buf->data, run->ft->frame->data, US_MIN(run->ft->frame->used, buf->allocated));
_D_LOG_DEBUG("Exposing STUB framebuffer n_buf=%u ...", run->stub_n_buf); _LOG_DEBUG("Exposing STUB framebuffer n_buf=%u ...", run->stub_n_buf);
const int retval = drmModePageFlip( const int retval = drmModePageFlip(
run->fd, run->crtc_id, buf->id, run->fd, run->crtc_id, buf->id,
DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC,
buf); buf);
if (retval < 0) { if (retval < 0) {
_D_LOG_PERROR("Can't expose STUB framebuffer n_buf=%u ...", run->stub_n_buf); _LOG_PERROR("Can't expose STUB framebuffer n_buf=%u ...", run->stub_n_buf);
} }
_D_LOG_DEBUG("Exposed STUB framebuffer n_buf=%u", run->stub_n_buf); _LOG_DEBUG("Exposed STUB framebuffer n_buf=%u", run->stub_n_buf);
run->stub_n_buf = (run->stub_n_buf + 1) % run->n_bufs; run->stub_n_buf = (run->stub_n_buf + 1) % run->n_bufs;
return retval; 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_runtime_s *const run = drm->run;
us_drm_buffer_s *const buf = &run->bufs[hw->buf.index]; us_drm_buffer_s *const buf = &run->bufs[hw->buf.index];
assert(run->fd >= 0); assert(run->fd >= 0);
assert(!run->opened_for_stub); assert(run->opened == 0);
run->blank_at_ts = 0;
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
case -2: return -2; case US_ERROR_NO_DEVICE: return US_ERROR_NO_DEVICE;
default: return -1; default: return -1;
} }
_drm_ensure_dpms_power(drm, true); _drm_ensure_dpms_power(drm, true);
run->has_vsync = false; run->has_vsync = false;
_D_LOG_DEBUG("Exposing DMA framebuffer n_buf=%u ...", hw->buf.index); _LOG_DEBUG("Exposing DMA framebuffer n_buf=%u ...", hw->buf.index);
const int retval = drmModePageFlip( const int retval = drmModePageFlip(
run->fd, run->crtc_id, buf->id, run->fd, run->crtc_id, buf->id,
DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_ASYNC,
buf); buf);
if (retval < 0) { if (retval < 0) {
_D_LOG_PERROR("Can't expose DMA framebuffer n_buf=%u ...", run->stub_n_buf); _LOG_PERROR("Can't expose DMA framebuffer n_buf=%u ...", run->stub_n_buf);
} }
_D_LOG_DEBUG("Exposed DMA framebuffer n_buf=%u", run->stub_n_buf); _LOG_DEBUG("Exposed DMA framebuffer n_buf=%u", run->stub_n_buf);
run->exposing_dma_fd = hw->dma_fd; run->exposing_dma_fd = hw->dma_fd;
return retval; return retval;
} }
@@ -409,36 +442,36 @@ static int _drm_check_status(us_drm_s *drm) {
us_drm_runtime_s *run = drm->run; us_drm_runtime_s *run = drm->run;
if (run->status_fd < 0) { if (run->status_fd < 0) {
_D_LOG_DEBUG("Trying to find status file ..."); _LOG_DEBUG("Trying to find status file ...");
struct stat st; struct stat st;
if (stat(drm->path, &st) < 0) { if (stat(drm->path, &st) < 0) {
_D_LOG_PERROR("Can't stat() DRM device"); _LOG_PERROR("Can't stat() DRM device");
goto error; goto error;
} }
const uint mi = minor(st.st_rdev); const uint mi = minor(st.st_rdev);
_D_LOG_DEBUG("DRM device minor(st_rdev)=%u", mi); _LOG_DEBUG("DRM device minor(st_rdev)=%u", mi);
char path[128]; char path[128];
US_SNPRINTF(path, 127, "/sys/class/drm/card%u-%s/status", mi, drm->port); US_SNPRINTF(path, 127, "/sys/class/drm/card%u-%s/status", mi, drm->port);
_D_LOG_DEBUG("Opening status file %s ...", path); _LOG_DEBUG("Opening status file %s ...", path);
if ((run->status_fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { if ((run->status_fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
_D_LOG_PERROR("Can't open status file: %s", path); _LOG_PERROR("Can't open status file: %s", path);
goto error; goto error;
} }
_D_LOG_DEBUG("Status file fd=%d opened", run->status_fd); _LOG_DEBUG("Status file fd=%d opened", run->status_fd);
} }
char status_ch; char status_ch;
if (read(run->status_fd, &status_ch, 1) != 1) { if (read(run->status_fd, &status_ch, 1) != 1) {
_D_LOG_PERROR("Can't read status file"); _LOG_PERROR("Can't read status file");
goto error; goto error;
} }
if (lseek(run->status_fd, 0, SEEK_SET) != 0) { if (lseek(run->status_fd, 0, SEEK_SET) != 0) {
_D_LOG_PERROR("Can't rewind status file"); _LOG_PERROR("Can't rewind status file");
goto error; goto error;
} }
_D_LOG_DEBUG("Current display status: %c", status_ch); _LOG_DEBUG("Current display status: %c", status_ch);
return (status_ch == 'd' ? -2 : 0); return (status_ch == 'd' ? US_ERROR_NO_DEVICE : 0);
error: error:
US_CLOSE_FD(run->status_fd); US_CLOSE_FD(run->status_fd);
@@ -448,24 +481,26 @@ error:
static void _drm_ensure_dpms_power(us_drm_s *drm, bool on) { static void _drm_ensure_dpms_power(us_drm_s *drm, bool on) {
us_drm_runtime_s *const run = drm->run; us_drm_runtime_s *const run = drm->run;
if (run->dpms_id > 0 && run->dpms_state != (int)on) { if (run->dpms_id > 0 && run->dpms_state != (int)on) {
_D_LOG_INFO("Changing DPMS power mode: %d -> %u ...", run->dpms_state, on); _LOG_INFO("Changing DPMS power mode: %d -> %u ...", run->dpms_state, on);
if (drmModeConnectorSetProperty( if (drmModeConnectorSetProperty(
run->fd, run->conn_id, run->dpms_id, run->fd, run->conn_id, run->dpms_id,
(on ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF) (on ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)
) < 0) { ) < 0) {
_D_LOG_PERROR("Can't set DPMS power=%u (ignored)", on); _LOG_PERROR("Can't set DPMS power=%u (ignored)", on);
} }
} }
run->dpms_state = (int)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; us_drm_runtime_s *const run = drm->run;
const uint n_bufs = (dev == NULL ? 4 : dev->run->n_bufs); const uint n_bufs = (cap == NULL ? 4 : cap->run->n_bufs);
const char *name = (dev == NULL ? "STUB" : "DMA"); const char *name = (cap == NULL ? "STUB" : "DMA");
_D_LOG_DEBUG("Initializing %u %s buffers ...", n_bufs, name); _LOG_DEBUG("Initializing %u %s buffers ...", n_bufs, name);
uint format = DRM_FORMAT_RGB888;
US_CALLOC(run->bufs, n_bufs); US_CALLOC(run->bufs, n_bufs);
for (run->n_bufs = 0; run->n_bufs < n_bufs; ++run->n_bufs) { for (run->n_bufs = 0; run->n_bufs < n_bufs; ++run->n_bufs) {
@@ -479,14 +514,14 @@ static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
u32 strides[4] = {0}; u32 strides[4] = {0};
u32 offsets[4] = {0}; u32 offsets[4] = {0};
if (dev == NULL) { if (cap == NULL) {
struct drm_mode_create_dumb create = { struct drm_mode_create_dumb create = {
.width = run->mode.hdisplay, .width = run->mode.hdisplay,
.height = run->mode.vdisplay, .height = run->mode.vdisplay,
.bpp = 24, .bpp = 24,
}; };
if (drmIoctl(run->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create) < 0) { if (drmIoctl(run->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create) < 0) {
_D_LOG_PERROR("Can't create %s buffer=%u", name, n_buf); _LOG_PERROR("Can't create %s buffer=%u", name, n_buf);
return -1; return -1;
} }
buf->handle = create.handle; buf->handle = create.handle;
@@ -494,7 +529,7 @@ static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
struct drm_mode_map_dumb map = {.handle = create.handle}; struct drm_mode_map_dumb map = {.handle = create.handle};
if (drmIoctl(run->fd, DRM_IOCTL_MODE_MAP_DUMB, &map) < 0) { if (drmIoctl(run->fd, DRM_IOCTL_MODE_MAP_DUMB, &map) < 0) {
_D_LOG_PERROR("Can't prepare dumb buffer=%u to mapping", n_buf); _LOG_PERROR("Can't prepare dumb buffer=%u to mapping", n_buf);
return -1; return -1;
} }
if ((buf->data = mmap( if ((buf->data = mmap(
@@ -502,7 +537,7 @@ static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
PROT_READ | PROT_WRITE, MAP_SHARED, PROT_READ | PROT_WRITE, MAP_SHARED,
run->fd, map.offset run->fd, map.offset
)) == MAP_FAILED) { )) == MAP_FAILED) {
_D_LOG_PERROR("Can't map buffer=%u", n_buf); _LOG_PERROR("Can't map buffer=%u", n_buf);
return -1; return -1;
} }
memset(buf->data, 0, create.size); memset(buf->data, 0, create.size);
@@ -512,20 +547,25 @@ static int _drm_init_buffers(us_drm_s *drm, const us_device_s *dev) {
strides[0] = create.pitch; strides[0] = create.pitch;
} else { } 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); _LOG_PERROR("Can't import DMA buffer=%u from capture device", n_buf);
return -1; return -1;
} }
handles[0] = buf->handle; 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( if (drmModeAddFB2(
run->fd, run->fd,
run->mode.hdisplay, run->mode.vdisplay, DRM_FORMAT_RGB888, run->mode.hdisplay, run->mode.vdisplay, format,
handles, strides, offsets, &buf->id, 0 handles, strides, offsets, &buf->id, 0
)) { )) {
_D_LOG_PERROR("Can't setup buffer=%u", n_buf); _LOG_PERROR("Can't setup buffer=%u", n_buf);
return -1; return -1;
} }
buf->fb_added = true; buf->fb_added = true;
@@ -538,22 +578,22 @@ static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz) {
run->crtc_id = 0; run->crtc_id = 0;
_D_LOG_DEBUG("Trying to find the appropriate sink ..."); _LOG_DEBUG("Trying to find the appropriate sink ...");
drmModeRes *res = drmModeGetResources(run->fd); drmModeRes *res = drmModeGetResources(run->fd);
if (res == NULL) { if (res == NULL) {
_D_LOG_PERROR("Can't get resources info"); _LOG_PERROR("Can't get resources info");
goto done; goto done;
} }
if (res->count_connectors <= 0) { if (res->count_connectors <= 0) {
_D_LOG_ERROR("Can't find any connectors"); _LOG_ERROR("Can't find any connectors");
goto done; goto done;
} }
for (int ci = 0; ci < res->count_connectors; ++ci) { for (int ci = 0; ci < res->count_connectors; ++ci) {
drmModeConnector *conn = drmModeGetConnector(run->fd, res->connectors[ci]); drmModeConnector *conn = drmModeGetConnector(run->fd, res->connectors[ci]);
if (conn == NULL) { if (conn == NULL) {
_D_LOG_PERROR("Can't get connector index=%d", ci); _LOG_PERROR("Can't get connector index=%d", ci);
goto done; goto done;
} }
@@ -565,37 +605,37 @@ static int _drm_find_sink(us_drm_s *drm, uint width, uint height, float hz) {
drmModeFreeConnector(conn); drmModeFreeConnector(conn);
continue; continue;
} }
_D_LOG_INFO("Using connector %s: conn_type=%d, conn_type_id=%d", _LOG_INFO("Using connector %s: conn_type=%d, conn_type_id=%d",
drm->port, conn->connector_type, conn->connector_type_id); drm->port, conn->connector_type, conn->connector_type_id);
if (conn->connection != DRM_MODE_CONNECTED) { if (conn->connection != DRM_MODE_CONNECTED) {
_D_LOG_ERROR("Connector for port %s has !DRM_MODE_CONNECTED", drm->port); _LOG_ERROR("Connector for port %s has !DRM_MODE_CONNECTED", drm->port);
drmModeFreeConnector(conn); drmModeFreeConnector(conn);
goto done; goto done;
} }
drmModeModeInfo *best; const drmModeModeInfo *best;
if ((best = _find_best_mode(conn, width, height, hz)) == NULL) { if ((best = _find_best_mode(conn, width, height, hz)) == NULL) {
_D_LOG_ERROR("Can't find any appropriate display modes"); _LOG_ERROR("Can't find any appropriate display modes");
drmModeFreeConnector(conn); drmModeFreeConnector(conn);
goto unplugged; goto unplugged;
} }
_D_LOG_INFO("Using best mode: %ux%up%.02f", _LOG_INFO("Using best mode: %ux%up%.02f",
best->hdisplay, best->vdisplay, _get_refresh_rate(best)); best->hdisplay, best->vdisplay, _get_refresh_rate(best));
if ((run->dpms_id = _find_dpms(run->fd, conn)) > 0) { if ((run->dpms_id = _find_dpms(run->fd, conn)) > 0) {
_D_LOG_INFO("Using DPMS: id=%u", run->dpms_id); _LOG_INFO("Using DPMS: id=%u", run->dpms_id);
} else { } else {
_D_LOG_INFO("Using DPMS: None"); _LOG_INFO("Using DPMS: None");
} }
u32 taken_crtcs = 0; // Unused here u32 taken_crtcs = 0; // Unused here
if ((run->crtc_id = _find_crtc(run->fd, res, conn, &taken_crtcs)) == 0) { if ((run->crtc_id = _find_crtc(run->fd, res, conn, &taken_crtcs)) == 0) {
_D_LOG_ERROR("Can't find CRTC"); _LOG_ERROR("Can't find CRTC");
drmModeFreeConnector(conn); drmModeFreeConnector(conn);
goto done; goto done;
} }
_D_LOG_INFO("Using CRTC: id=%u", run->crtc_id); _LOG_INFO("Using CRTC: id=%u", run->crtc_id);
run->conn_id = conn->connector_id; run->conn_id = conn->connector_id;
memcpy(&run->mode, best, sizeof(drmModeModeInfo)); memcpy(&run->mode, best, sizeof(drmModeModeInfo));
@@ -610,7 +650,7 @@ done:
unplugged: unplugged:
drmModeFreeResources(res); drmModeFreeResources(res);
return -2; return US_ERROR_NO_DEVICE;
} }
static drmModeModeInfo *_find_best_mode(drmModeConnector *conn, uint width, uint height, float hz) { static drmModeModeInfo *_find_best_mode(drmModeConnector *conn, uint width, uint height, float hz) {

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -25,10 +25,10 @@
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "../libs/types.h" #include "../types.h"
#include "../libs/frame.h" #include "../frame.h"
#include "../libs/frametext.h" #include "../frametext.h"
#include "../libs/device.h" #include "../capture.h"
typedef enum { typedef enum {
@@ -63,11 +63,14 @@ typedef struct {
uint n_bufs; uint n_bufs;
drmModeCrtc *saved_crtc; drmModeCrtc *saved_crtc;
int dpms_state; int dpms_state;
bool opened_for_stub; int opened;
bool has_vsync; bool has_vsync;
int exposing_dma_fd; int exposing_dma_fd;
uint stub_n_buf; uint stub_n_buf;
bool unplugged_reported; ldf blank_at_ts;
int once;
us_frametext_s *ft; us_frametext_s *ft;
} us_drm_runtime_s; } us_drm_runtime_s;
@@ -75,6 +78,7 @@ typedef struct {
char *path; char *path;
char *port; char *port;
uint timeout; uint timeout;
uint blank_after;
us_drm_runtime_s *run; us_drm_runtime_s *run;
} us_drm_s; } us_drm_s;
@@ -83,10 +87,11 @@ typedef struct {
us_drm_s *us_drm_init(void); us_drm_s *us_drm_init(void);
void us_drm_destroy(us_drm_s *drm); 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); void us_drm_close(us_drm_s *drm);
int us_drm_dpms_power_off(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_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_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_hw_buffer_s *hw); int us_drm_expose_dma(us_drm_s *drm, const us_capture_hwbuf_s *hw);
int us_drm_ensure_no_signal(us_drm_s *drm);

27
src/libs/errors.h Normal file
View File

@@ -0,0 +1,27 @@
/*****************************************************************************
# #
# 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/>. #
# #
*****************************************************************************/
#pragma once
#define US_ERROR_COMMON -1
#define US_ERROR_NO_DEVICE -2
#define US_ERROR_NO_DATA -3

112
src/libs/fpsi.c Normal file
View File

@@ -0,0 +1,112 @@
/*****************************************************************************
# #
# 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 "fpsi.h"
#include <stdatomic.h>
#include <pthread.h>
#include "types.h"
#include "tools.h"
#include "threading.h"
#include "logging.h"
#include "frame.h"
us_fpsi_s *us_fpsi_init(const char *name, bool with_meta) {
us_fpsi_s *fpsi;
US_CALLOC(fpsi, 1);
fpsi->name = us_strdup(name);
fpsi->with_meta = with_meta;
atomic_init(&fpsi->state_sec_ts, 0);
atomic_init(&fpsi->state, 0);
return fpsi;
}
void us_fpsi_destroy(us_fpsi_s *fpsi) {
free(fpsi->name);
free(fpsi);
}
void us_fpsi_frame_to_meta(const us_frame_s *frame, us_fpsi_meta_s *meta) {
meta->width = frame->width;
meta->height = frame->height;
meta->online = frame->online;
}
void us_fpsi_update(us_fpsi_s *fpsi, bool bump, const us_fpsi_meta_s *meta) {
if (meta != NULL) {
assert(fpsi->with_meta);
} else {
assert(!fpsi->with_meta);
}
const sll now_sec_ts = us_floor_ms(us_get_now_monotonic());
if (atomic_load(&fpsi->state_sec_ts) != now_sec_ts) {
US_LOG_PERF_FPS("FPS: %s: %u", fpsi->name, fpsi->accum);
// Fast mutex-less store method
ull state = (ull)fpsi->accum & 0xFFFF;
if (fpsi->with_meta) {
assert(meta != NULL);
state |= (ull)(meta->width & 0xFFFF) << 16;
state |= (ull)(meta->height & 0xFFFF) << 32;
state |= (ull)(meta->online ? 1 : 0) << 48;
}
atomic_store(&fpsi->state, state); // Сначала инфа
atomic_store(&fpsi->state_sec_ts, now_sec_ts); // Потом время, это важно
fpsi->accum = 0;
}
if (bump) {
++fpsi->accum;
}
}
uint us_fpsi_get(us_fpsi_s *fpsi, us_fpsi_meta_s *meta) {
if (meta != NULL) {
assert(fpsi->with_meta);
} else {
assert(!fpsi->with_meta);
}
// Между чтением инфы и времени может быть гонка,
// но это неважно. Если время свежее, до данные тоже
// будут свежмими, обратный случай не так важен.
const sll now_sec_ts = us_floor_ms(us_get_now_monotonic());
const sll state_sec_ts = atomic_load(&fpsi->state_sec_ts); // Сначала время
const ull state = atomic_load(&fpsi->state); // Потом инфа
uint current = state & 0xFFFF;
if (fpsi->with_meta) {
assert(meta != NULL);
meta->width = (state >> 16) & 0xFFFF;
meta->height = (state >> 32) & 0xFFFF;
meta->online = (state >> 48) & 1;
}
if (state_sec_ts != now_sec_ts && (state_sec_ts + 1) != now_sec_ts) {
// Только текущая или прошлая секунда
current = 0;
}
return current;
}

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -24,23 +24,28 @@
#include <stdatomic.h> #include <stdatomic.h>
#include "../libs/types.h" #include "types.h"
#include "../libs/frame.h" #include "frame.h"
#include "../libs/memsink.h"
#include "m2m.h"
typedef struct { typedef struct {
us_memsink_s *sink; uint width;
bool key_requested; uint height;
us_frame_s *tmp_src; bool online;
us_frame_s *dest; } us_fpsi_meta_s;
us_m2m_encoder_s *enc;
atomic_bool online; typedef struct {
} us_h264_stream_s; char *name;
bool with_meta;
uint accum;
atomic_llong state_sec_ts;
atomic_ullong state;
} us_fpsi_s;
us_h264_stream_s *us_h264_stream_init(us_memsink_s *sink, const char *path, uint bitrate, uint gop); us_fpsi_s *us_fpsi_init(const char *name, bool with_meta);
void us_h264_stream_destroy(us_h264_stream_s *h264); void us_fpsi_destroy(us_fpsi_s *fpsi);
void us_h264_stream_process(us_h264_stream_s *h264, const us_frame_s *frame, bool force_key);
void us_fpsi_frame_to_meta(const us_frame_s *frame, us_fpsi_meta_s *meta);
void us_fpsi_update(us_fpsi_s *fpsi, bool bump, const us_fpsi_meta_s *meta);
uint us_fpsi_get(us_fpsi_s *fpsi, us_fpsi_meta_s *meta);

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -26,54 +26,58 @@
#include "tools.h" #include "tools.h"
#define US_FRAME_META_DECLARE \
uint width; \
uint height; \
uint format; \
uint stride; \
/* Stride is a bytesperline in V4L2 */ \
/* https://www.kernel.org/doc/html/v4.14/media/uapi/v4l/pixfmt-v4l2.html */ \
/* https://medium.com/@oleg.shipitko/what-does-stride-mean-in-image-processing-bba158a72bcd */ \
bool online; \
bool key; \
uint gop; \
\
ldf grab_ts; \
ldf encode_begin_ts; \
ldf encode_end_ts;
typedef struct { typedef struct {
u8 *data; u8 *data;
uz used; uz used;
uz allocated; uz allocated;
int dma_fd; int dma_fd;
uint width; US_FRAME_META_DECLARE;
uint height;
uint format;
uint stride;
// Stride is a bytesperline in V4L2
// https://www.kernel.org/doc/html/v4.14/media/uapi/v4l/pixfmt-v4l2.html
// https://medium.com/@oleg.shipitko/what-does-stride-mean-in-image-processing-bba158a72bcd
bool online;
bool key;
uint gop;
ldf grab_ts;
ldf encode_begin_ts;
ldf encode_end_ts;
} us_frame_s; } us_frame_s;
#define US_FRAME_COPY_META(x_src, x_dest) { \ #define US_FRAME_COPY_META(x_src, x_dest) { \
x_dest->width = x_src->width; \ (x_dest)->width = (x_src)->width; \
x_dest->height = x_src->height; \ (x_dest)->height = (x_src)->height; \
x_dest->format = x_src->format; \ (x_dest)->format = (x_src)->format; \
x_dest->stride = x_src->stride; \ (x_dest)->stride = (x_src)->stride; \
x_dest->online = x_src->online; \ (x_dest)->online = (x_src)->online; \
x_dest->key = x_src->key; \ (x_dest)->key = (x_src)->key; \
x_dest->gop = x_src->gop; \ (x_dest)->gop = (x_src)->gop; \
\ \
x_dest->grab_ts = x_src->grab_ts; \ (x_dest)->grab_ts = (x_src)->grab_ts; \
x_dest->encode_begin_ts = x_src->encode_begin_ts; \ (x_dest)->encode_begin_ts = (x_src)->encode_begin_ts; \
x_dest->encode_end_ts = x_src->encode_end_ts; \ (x_dest)->encode_end_ts = (x_src)->encode_end_ts; \
} }
#define US_FRAME_COMPARE_GEOMETRY(x_a, x_b) ( \ #define US_FRAME_COMPARE_GEOMETRY(x_a, x_b) ( \
/* Compare the used size and significant meta (no timings) */ \ /* Compare the used size and significant meta (no timings) */ \
x_a->used == x_b->used \ (x_a)->used == (x_b)->used \
\ \
&& x_a->width == x_b->width \ && (x_a)->width == (x_b)->width \
&& x_a->height == x_b->height \ && (x_a)->height == (x_b)->height \
&& x_a->format == x_b->format \ && (x_a)->format == (x_b)->format \
&& x_a->stride == x_b->stride \ && (x_a)->stride == (x_b)->stride \
&& x_a->online == x_b->online \ && (x_a)->online == (x_b)->online \
&& x_a->key == x_b->key \ && (x_a)->key == (x_b)->key \
&& x_a->gop == x_b->gop \ && (x_a)->gop == (x_b)->gop \
) )

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -25,9 +25,9 @@
#include <assert.h> #include <assert.h>
#define US_LIST_STRUCT(...) \ #define US_LIST_DECLARE \
__VA_ARGS__ *prev; \ void *prev; \
__VA_ARGS__ *next; void *next;
#define US_LIST_ITERATE(x_first, x_item, ...) { \ #define US_LIST_ITERATE(x_first, x_item, ...) { \
for (__typeof__(x_first) x_item = x_first; x_item;) { \ for (__typeof__(x_first) x_item = x_first; x_item;) { \
@@ -42,10 +42,11 @@
x_first = x_item; \ x_first = x_item; \
} else { \ } else { \
__typeof__(x_first) m_last = x_first; \ __typeof__(x_first) m_last = x_first; \
for (; m_last->next; m_last = m_last->next); \ for (; m_last->next != NULL; m_last = m_last->next); \
x_item->prev = m_last; \ x_item->prev = m_last; \
m_last->next = x_item; \ m_last->next = x_item; \
} \ } \
x_item->next = NULL; \
} }
#define US_LIST_APPEND_C(x_first, x_item, x_count) { \ #define US_LIST_APPEND_C(x_first, x_item, x_count) { \
@@ -57,11 +58,15 @@
if (x_item->prev == NULL) { \ if (x_item->prev == NULL) { \
x_first = x_item->next; \ x_first = x_item->next; \
} else { \ } else { \
x_item->prev->next = x_item->next; \ __typeof__(x_first) m_prev = x_item->prev; \
m_prev->next = x_item->next; \
} \ } \
if (x_item->next != NULL) { \ if (x_item->next != NULL) { \
x_item->next->prev = x_item->prev; \ __typeof__(x_first) m_next = x_item->next; \
m_next->prev = x_item->prev; \
} \ } \
x_item->prev = NULL; \
x_item->next = NULL; \
} }
#define US_LIST_REMOVE_C(x_first, x_item, x_count) { \ #define US_LIST_REMOVE_C(x_first, x_item, x_count) { \

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -33,13 +33,14 @@
#include <sys/mman.h> #include <sys/mman.h>
#include "types.h" #include "types.h"
#include "errors.h"
#include "tools.h" #include "tools.h"
#include "logging.h" #include "logging.h"
#include "frame.h" #include "frame.h"
#include "memsinksh.h" #include "memsinksh.h"
us_memsink_s *us_memsink_init( us_memsink_s *us_memsink_init_opened(
const char *name, const char *obj, bool server, const char *name, const char *obj, bool server,
mode_t mode, bool rm, uint client_ttl, uint timeout) { mode_t mode, bool rm, uint client_ttl, uint timeout) {
@@ -168,7 +169,7 @@ int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key
if (frame->used > sink->data_size) { if (frame->used > sink->data_size) {
US_LOG_ERROR("%s-sink: Can't put frame: is too big (%zu > %zu)", US_LOG_ERROR("%s-sink: Can't put frame: is too big (%zu > %zu)",
sink->name, frame->used, sink->data_size); sink->name, frame->used, sink->data_size);
return 0; // -2 return 0;
} }
if (us_flock_timedwait_monotonic(sink->fd, 1) == 0) { if (us_flock_timedwait_monotonic(sink->fd, 1) == 0) {
@@ -213,7 +214,7 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_reque
if (us_flock_timedwait_monotonic(sink->fd, sink->timeout) < 0) { if (us_flock_timedwait_monotonic(sink->fd, sink->timeout) < 0) {
if (errno == EWOULDBLOCK) { if (errno == EWOULDBLOCK) {
return -2; return US_ERROR_NO_DATA;
} }
US_LOG_PERROR("%s-sink: Can't lock memory", sink->name); US_LOG_PERROR("%s-sink: Can't lock memory", sink->name);
return -1; return -1;
@@ -222,7 +223,7 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_reque
int retval = 0; int retval = 0;
if (sink->mem->magic != US_MEMSINK_MAGIC) { if (sink->mem->magic != US_MEMSINK_MAGIC) {
retval = -2; // Not updated retval = US_ERROR_NO_DATA; // Not updated
goto done; goto done;
} }
if (sink->mem->version != US_MEMSINK_VERSION) { if (sink->mem->version != US_MEMSINK_VERSION) {
@@ -236,7 +237,7 @@ int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_reque
sink->mem->last_client_ts = us_get_now_monotonic(); sink->mem->last_client_ts = us_get_now_monotonic();
if (sink->mem->id == sink->last_readed_id) { if (sink->mem->id == sink->last_readed_id) {
retval = -2; // Not updated retval = US_ERROR_NO_DATA; // Not updated
goto done; goto done;
} }

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -50,7 +50,7 @@ typedef struct {
} us_memsink_s; } us_memsink_s;
us_memsink_s *us_memsink_init( us_memsink_s *us_memsink_init_opened(
const char *name, const char *obj, bool server, const char *name, const char *obj, bool server,
mode_t mode, bool rm, uint client_ttl, uint timeout); mode_t mode, bool rm, uint client_ttl, uint timeout);

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -68,5 +68,5 @@ uz us_memsink_calculate_size(const char *obj) {
} }
u8 *us_memsink_get_data(us_memsink_shared_s *mem) { u8 *us_memsink_get_data(us_memsink_shared_s *mem) {
return (u8*)(mem + sizeof(us_memsink_shared_s)); return (u8*)(mem) + sizeof(us_memsink_shared_s);
} }

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -23,33 +23,23 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "frame.h"
#define US_MEMSINK_MAGIC ((u64)0xCAFEBABECAFEBABE) #define US_MEMSINK_MAGIC ((u64)0xCAFEBABECAFEBABE)
#define US_MEMSINK_VERSION ((u32)5) #define US_MEMSINK_VERSION ((u32)7)
typedef struct { typedef struct {
u64 magic; u64 magic;
u32 version; u32 version;
u64 id; u64 id;
uz used; uz used;
uint width;
uint height;
uint format;
uint stride;
bool online;
bool key;
uint gop;
ldf grab_ts;
ldf encode_begin_ts;
ldf encode_end_ts;
ldf last_client_ts; ldf last_client_ts;
bool key_requested; bool key_requested;
US_FRAME_META_DECLARE;
} us_memsink_shared_s; } us_memsink_shared_s;

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -58,7 +58,7 @@ int us_tc358743_xioctl_get_audio_hz(int fd, uint *audio_hz) {
US_MEMSET_ZERO(ctl); US_MEMSET_ZERO(ctl);
ctl.id = TC358743_CID_AUDIO_SAMPLING_RATE; ctl.id = TC358743_CID_AUDIO_SAMPLING_RATE;
if (us_xioctl(fd, VIDIOC_G_CTRL, &ctl) < 0) { if (us_xioctl(fd, VIDIOC_G_CTRL, &ctl) < 0) {
return -2; return -1;
} }
*audio_hz = ctl.value; *audio_hz = ctl.value;
return 0; return 0;

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -113,7 +113,9 @@ INLINE void us_thread_get_name(char *name) { // Always required for logging
#if defined(__linux__) #if defined(__linux__)
const pid_t tid = syscall(SYS_gettid); const pid_t tid = syscall(SYS_gettid);
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
const pid_t tid = syscall(SYS_thr_self); long id;
assert(!syscall(SYS_thr_self, &id));
const pid_t tid = id;
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
const pid_t tid = syscall(SYS_getthrid); const pid_t tid = syscall(SYS_getthrid);
#elif defined(__NetBSD__) #elif defined(__NetBSD__)

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -72,14 +72,16 @@
(m_a > m_b ? m_a : m_b); \ (m_a > m_b ? m_a : m_b); \
}) })
#define US_ONCE(...) { \ #define US_ONCE_FOR(x_once, x_value, ...) { \
const int m_reported = __LINE__; \ const int m_reported = (x_value); \
if (m_reported != once) { \ if (m_reported != (x_once)) { \
__VA_ARGS__; \ __VA_ARGS__; \
once = m_reported; \ (x_once) = m_reported; \
} \ } \
} }
#define US_ONCE(...) US_ONCE_FOR(once, __LINE__, ##__VA_ARGS__)
INLINE char *us_strdup(const char *str) { INLINE char *us_strdup(const char *str) {
char *const new = strdup(str); char *const new = strdup(str);

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -25,6 +25,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h>
typedef long long sll; typedef long long sll;
typedef ssize_t sz; typedef ssize_t sz;

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -22,6 +22,26 @@
#include "encoder.h" #include "encoder.h"
#include <stdlib.h>
#include <strings.h>
#include <assert.h>
#include <pthread.h>
#include "../libs/types.h"
#include "../libs/tools.h"
#include "../libs/array.h"
#include "../libs/threading.h"
#include "../libs/logging.h"
#include "../libs/frame.h"
#include "../libs/capture.h"
#include "workers.h"
#include "m2m.h"
#include "encoders/cpu/encoder.h"
#include "encoders/hw/encoder.h"
static const struct { static const struct {
const char *name; const char *name;
@@ -34,7 +54,7 @@ static const struct {
{"M2M-MJPEG", US_ENCODER_TYPE_M2M_VIDEO}, {"M2M-MJPEG", US_ENCODER_TYPE_M2M_VIDEO},
{"M2M-JPEG", US_ENCODER_TYPE_M2M_IMAGE}, {"M2M-JPEG", US_ENCODER_TYPE_M2M_IMAGE},
{"OMX", US_ENCODER_TYPE_M2M_IMAGE}, {"OMX", US_ENCODER_TYPE_M2M_IMAGE},
{"NOOP", US_ENCODER_TYPE_NOOP}, {"NOOP", US_ENCODER_TYPE_CPU},
}; };
@@ -43,9 +63,6 @@ static void _worker_job_destroy(void *v_job);
static bool _worker_run_job(us_worker_s *wr); static bool _worker_run_job(us_worker_s *wr);
#define _ER(x_next) enc->run->x_next
us_encoder_s *us_encoder_init(void) { us_encoder_s *us_encoder_init(void) {
us_encoder_runtime_s *run; us_encoder_runtime_s *run;
US_CALLOC(run, 1); US_CALLOC(run, 1);
@@ -62,14 +79,15 @@ us_encoder_s *us_encoder_init(void) {
} }
void us_encoder_destroy(us_encoder_s *enc) { void us_encoder_destroy(us_encoder_s *enc) {
if (_ER(m2ms) != NULL) { us_encoder_runtime_s *const run = enc->run;
for (unsigned index = 0; index < _ER(n_m2ms); ++index) { if (run->m2ms != NULL) {
US_DELETE(_ER(m2ms[index]), us_m2m_encoder_destroy) for (uint index = 0; index < run->n_m2ms; ++index) {
US_DELETE(run->m2ms[index], us_m2m_encoder_destroy);
} }
free(_ER(m2ms)); free(run->m2ms);
} }
US_MUTEX_DESTROY(_ER(mutex)); US_MUTEX_DESTROY(run->mutex);
free(enc->run); free(run);
free(enc); free(enc);
} }
@@ -91,86 +109,70 @@ const char *us_encoder_type_to_string(us_encoder_type_e type) {
return _ENCODER_TYPES[0].name; 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); us_encoder_runtime_s *const run = enc->run;
us_capture_runtime_s *const cr = cap->run;
# define DR(x_next) dev->run->x_next assert(run->pool == NULL);
us_encoder_type_e type = (_ER(cpu_forced) ? US_ENCODER_TYPE_CPU : enc->type); us_encoder_type_e type = enc->type;
unsigned quality = dev->jpeg_quality; uint quality = cap->jpeg_quality;
unsigned n_workers = US_MIN(enc->n_workers, DR(n_bufs)); uint n_workers = US_MIN(enc->n_workers, cr->n_bufs);
bool cpu_forced = false;
if (us_is_jpeg(DR(format)) && type != US_ENCODER_TYPE_HW) { if (us_is_jpeg(cr->format) && type != US_ENCODER_TYPE_HW) {
US_LOG_INFO("Switching to HW encoder: the input is (M)JPEG ..."); US_LOG_INFO("Switching to HW encoder: the input is (M)JPEG ...");
type = US_ENCODER_TYPE_HW; type = US_ENCODER_TYPE_HW;
} }
if (type == US_ENCODER_TYPE_HW) { if (type == US_ENCODER_TYPE_HW) {
if (!us_is_jpeg(DR(format))) { if (us_is_jpeg(cr->format)) {
quality = cr->jpeg_quality;
n_workers = 1;
} else {
US_LOG_INFO("Switching to CPU encoder: the input format is not (M)JPEG ..."); US_LOG_INFO("Switching to CPU encoder: the input format is not (M)JPEG ...");
goto use_cpu; type = US_ENCODER_TYPE_CPU;
quality = cap->jpeg_quality;
} }
quality = DR(jpeg_quality);
n_workers = 1;
} else if (type == US_ENCODER_TYPE_M2M_VIDEO || type == US_ENCODER_TYPE_M2M_IMAGE) { } else if (type == US_ENCODER_TYPE_M2M_VIDEO || type == US_ENCODER_TYPE_M2M_IMAGE) {
US_LOG_DEBUG("Preparing M2M-%s encoder ...", (type == US_ENCODER_TYPE_M2M_VIDEO ? "VIDEO" : "IMAGE")); US_LOG_DEBUG("Preparing M2M-%s encoder ...", (type == US_ENCODER_TYPE_M2M_VIDEO ? "VIDEO" : "IMAGE"));
if (_ER(m2ms) == NULL) { if (run->m2ms == NULL) {
US_CALLOC(_ER(m2ms), n_workers); US_CALLOC(run->m2ms, n_workers);
} }
for (; _ER(n_m2ms) < n_workers; ++_ER(n_m2ms)) { for (; run->n_m2ms < n_workers; ++run->n_m2ms) {
// Начинаем с нуля и доинициализируем на следующих заходах при необходимости // Начинаем с нуля и доинициализируем на следующих заходах при необходимости
char name[32]; char name[32];
US_SNPRINTF(name, 31, "JPEG-%u", _ER(n_m2ms)); US_SNPRINTF(name, 31, "JPEG-%u", run->n_m2ms);
if (type == US_ENCODER_TYPE_M2M_VIDEO) { if (type == US_ENCODER_TYPE_M2M_VIDEO) {
_ER(m2ms[_ER(n_m2ms)]) = us_m2m_mjpeg_encoder_init(name, enc->m2m_path, quality); run->m2ms[run->n_m2ms] = us_m2m_mjpeg_encoder_init(name, enc->m2m_path, quality);
} else { } else {
_ER(m2ms[_ER(n_m2ms)]) = us_m2m_jpeg_encoder_init(name, enc->m2m_path, quality); run->m2ms[run->n_m2ms] = us_m2m_jpeg_encoder_init(name, enc->m2m_path, quality);
} }
} }
} else if (type == US_ENCODER_TYPE_NOOP) {
n_workers = 1;
quality = 0;
} }
goto ok; if (quality == 0) {
US_LOG_INFO("Using JPEG quality: encoder default");
} else {
US_LOG_INFO("Using JPEG quality: %u%%", quality);
}
use_cpu: US_MUTEX_LOCK(run->mutex);
type = US_ENCODER_TYPE_CPU; run->type = type;
quality = dev->jpeg_quality; run->quality = quality;
US_MUTEX_UNLOCK(run->mutex);
ok: const ldf desired_interval = (
if (type == US_ENCODER_TYPE_NOOP) { cap->desired_fps > 0 && (cap->desired_fps < cap->run->hw_fps || cap->run->hw_fps == 0)
US_LOG_INFO("Using JPEG NOOP encoder"); ? (ldf)1 / cap->desired_fps
} else if (quality == 0) { : 0
US_LOG_INFO("Using JPEG quality: encoder default"); );
} else {
US_LOG_INFO("Using JPEG quality: %u%%", quality);
}
US_MUTEX_LOCK(_ER(mutex)); enc->run->pool = us_workers_pool_init(
_ER(type) = type; "JPEG", "jw", n_workers, desired_interval,
_ER(quality) = quality; _worker_job_init, (void*)enc,
if (cpu_forced) { _worker_job_destroy,
_ER(cpu_forced) = true; _worker_run_job);
}
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
: 0
);
enc->run->pool = us_workers_pool_init(
"JPEG", "jw", n_workers, desired_interval,
_worker_job_init, (void*)enc,
_worker_job_destroy,
_worker_run_job);
# undef DR
} }
void us_encoder_close(us_encoder_s *enc) { void us_encoder_close(us_encoder_s *enc) {
@@ -178,11 +180,12 @@ void us_encoder_close(us_encoder_s *enc) {
US_DELETE(enc->run->pool, us_workers_pool_destroy); US_DELETE(enc->run->pool, us_workers_pool_destroy);
} }
void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, unsigned *quality) { void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, uint *quality) {
US_MUTEX_LOCK(_ER(mutex)); us_encoder_runtime_s *const run = enc->run;
*type = _ER(type); US_MUTEX_LOCK(run->mutex);
*quality = _ER(quality); *type = run->type;
US_MUTEX_UNLOCK(_ER(mutex)); *quality = run->quality;
US_MUTEX_UNLOCK(run->mutex);
} }
static void *_worker_job_init(void *v_enc) { static void *_worker_job_init(void *v_enc) {
@@ -200,35 +203,28 @@ static void _worker_job_destroy(void *v_job) {
} }
static bool _worker_run_job(us_worker_s *wr) { static bool _worker_run_job(us_worker_s *wr) {
us_encoder_job_s *job = wr->job; us_encoder_job_s *const job = wr->job;
us_encoder_s *enc = job->enc; // Just for _ER() us_encoder_runtime_s *const run = job->enc->run;
const us_frame_s *src = &job->hw->raw; const us_frame_s *const src = &job->hw->raw;
us_frame_s *dest = job->dest; us_frame_s *const dest = job->dest;
if (_ER(type) == US_ENCODER_TYPE_CPU) { if (run->type == US_ENCODER_TYPE_CPU) {
US_LOG_VERBOSE("Compressing JPEG using CPU: worker=%s, buffer=%u", US_LOG_VERBOSE("Compressing JPEG using CPU: worker=%s, buffer=%u",
wr->name, job->hw->buf.index); wr->name, job->hw->buf.index);
us_cpu_encoder_compress(src, dest, _ER(quality)); us_cpu_encoder_compress(src, dest, run->quality);
} else if (_ER(type) == US_ENCODER_TYPE_HW) { } else if (run->type == US_ENCODER_TYPE_HW) {
US_LOG_VERBOSE("Compressing JPEG using HW (just copying): worker=%s, buffer=%u", US_LOG_VERBOSE("Compressing JPEG using HW (just copying): worker=%s, buffer=%u",
wr->name, job->hw->buf.index); wr->name, job->hw->buf.index);
us_hw_encoder_compress(src, dest); us_hw_encoder_compress(src, dest);
} else if (_ER(type) == US_ENCODER_TYPE_M2M_VIDEO || _ER(type) == US_ENCODER_TYPE_M2M_IMAGE) { } else if (run->type == US_ENCODER_TYPE_M2M_VIDEO || run->type == US_ENCODER_TYPE_M2M_IMAGE) {
US_LOG_VERBOSE("Compressing JPEG using M2M-%s: worker=%s, buffer=%u", US_LOG_VERBOSE("Compressing JPEG using M2M-%s: worker=%s, buffer=%u",
(_ER(type) == US_ENCODER_TYPE_M2M_VIDEO ? "VIDEO" : "IMAGE"), wr->name, job->hw->buf.index); (run->type == US_ENCODER_TYPE_M2M_VIDEO ? "VIDEO" : "IMAGE"), wr->name, job->hw->buf.index);
if (us_m2m_encoder_compress(_ER(m2ms[wr->number]), src, dest, false) < 0) { if (us_m2m_encoder_compress(run->m2ms[wr->number], src, dest, false) < 0) {
goto error; goto error;
} }
} else if (_ER(type) == US_ENCODER_TYPE_NOOP) {
US_LOG_VERBOSE("Compressing JPEG using NOOP (do nothing): worker=%s, buffer=%u",
wr->name, job->hw->buf.index);
us_frame_encoding_begin(src, dest, V4L2_PIX_FMT_JPEG);
usleep(5000); // Просто чтобы работала логика desired_fps
dest->encode_end_ts = us_get_now_monotonic(); // us_frame_encoding_end()
} else { } else {
assert(0 && "Unknown encoder type"); assert(0 && "Unknown encoder type");
} }
@@ -238,14 +234,9 @@ static bool _worker_run_job(us_worker_s *wr) {
job->dest->encode_end_ts - job->dest->encode_begin_ts, job->dest->encode_end_ts - job->dest->encode_begin_ts,
wr->name, wr->name,
job->hw->buf.index); job->hw->buf.index);
return true; return true;
error: error:
US_LOG_ERROR("Compression failed: worker=%s, buffer=%u", wr->name, job->hw->buf.index); US_LOG_ERROR("Compression failed: worker=%s, buffer=%u", wr->name, job->hw->buf.index);
US_LOG_ERROR("Error while compressing buffer, falling back to CPU"); return false;
US_MUTEX_LOCK(_ER(mutex));
_ER(cpu_forced) = true;
US_MUTEX_UNLOCK(_ER(mutex));
return false;
} }

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -22,45 +22,32 @@
#pragma once #pragma once
#include <stdlib.h>
#include <stdbool.h>
#include <strings.h>
#include <assert.h>
#include <pthread.h> #include <pthread.h>
#include <linux/videodev2.h>
#include "../libs/tools.h" #include "../libs/types.h"
#include "../libs/array.h"
#include "../libs/threading.h"
#include "../libs/logging.h"
#include "../libs/frame.h" #include "../libs/frame.h"
#include "../libs/device.h" #include "../libs/capture.h"
#include "workers.h" #include "workers.h"
#include "m2m.h" #include "m2m.h"
#include "encoders/cpu/encoder.h"
#include "encoders/hw/encoder.h"
#define ENCODER_TYPES_STR "CPU, HW, M2M-VIDEO, M2M-IMAGE"
#define ENCODER_TYPES_STR "CPU, HW, M2M-VIDEO, M2M-IMAGE, NOOP"
typedef enum { typedef enum {
US_ENCODER_TYPE_CPU, US_ENCODER_TYPE_CPU,
US_ENCODER_TYPE_HW, US_ENCODER_TYPE_HW,
US_ENCODER_TYPE_M2M_VIDEO, US_ENCODER_TYPE_M2M_VIDEO,
US_ENCODER_TYPE_M2M_IMAGE, US_ENCODER_TYPE_M2M_IMAGE,
US_ENCODER_TYPE_NOOP,
} us_encoder_type_e; } us_encoder_type_e;
typedef struct { typedef struct {
us_encoder_type_e type; us_encoder_type_e type;
unsigned quality; uint quality;
bool cpu_forced;
pthread_mutex_t mutex; pthread_mutex_t mutex;
unsigned n_m2ms; uint n_m2ms;
us_m2m_encoder_s **m2ms; us_m2m_encoder_s **m2ms;
us_workers_pool_s *pool; us_workers_pool_s *pool;
@@ -68,16 +55,16 @@ typedef struct {
typedef struct { typedef struct {
us_encoder_type_e type; us_encoder_type_e type;
unsigned n_workers; uint n_workers;
char *m2m_path; char *m2m_path;
us_encoder_runtime_s *run; us_encoder_runtime_s *run;
} us_encoder_s; } us_encoder_s;
typedef struct { typedef struct {
us_encoder_s *enc; us_encoder_s *enc;
us_hw_buffer_s *hw; us_capture_hwbuf_s *hw;
us_frame_s *dest; us_frame_s *dest;
} us_encoder_job_s; } us_encoder_job_s;
@@ -87,7 +74,7 @@ void us_encoder_destroy(us_encoder_s *enc);
int us_encoder_parse_type(const char *str); int us_encoder_parse_type(const char *str);
const char *us_encoder_type_to_string(us_encoder_type_e type); 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_close(us_encoder_s *enc);
void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, unsigned *quality); void us_encoder_get_runtime_params(us_encoder_s *enc, us_encoder_type_e *type, uint *quality);

View File

@@ -7,7 +7,7 @@
# Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard # # Copyright (C) 2005-2006 Laurent Pinchart & Michel Xhaard #
# Copyright (C) 2006 Gabriel A. Devenyi # # Copyright (C) 2006 Gabriel A. Devenyi #
# Copyright (C) 2007 Tom Stöveken # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #
@@ -40,7 +40,10 @@ static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame);
static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
#ifndef JCS_EXTENSIONS
#warning JCS_EXT_BGR is not supported, please use libjpeg-turbo
static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame); static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame);
#endif
static void _jpeg_init_destination(j_compress_ptr jpeg); static void _jpeg_init_destination(j_compress_ptr jpeg);
static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg); static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg);
@@ -67,6 +70,9 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_UYVY: jpeg.in_color_space = JCS_YCbCr; break; case V4L2_PIX_FMT_UYVY: jpeg.in_color_space = JCS_YCbCr; break;
# ifdef JCS_EXTENSIONS
case V4L2_PIX_FMT_BGR24: jpeg.in_color_space = JCS_EXT_BGR; break;
# endif
default: jpeg.in_color_space = JCS_RGB; break; default: jpeg.in_color_space = JCS_RGB; break;
} }
@@ -82,7 +88,13 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, unsigned q
case V4L2_PIX_FMT_UYVY: _jpeg_write_scanlines_yuv(&jpeg, src); break; case V4L2_PIX_FMT_UYVY: _jpeg_write_scanlines_yuv(&jpeg, src); break;
case V4L2_PIX_FMT_RGB565: _jpeg_write_scanlines_rgb565(&jpeg, src); break; case V4L2_PIX_FMT_RGB565: _jpeg_write_scanlines_rgb565(&jpeg, src); break;
case V4L2_PIX_FMT_RGB24: _jpeg_write_scanlines_rgb24(&jpeg, src); break; case V4L2_PIX_FMT_RGB24: _jpeg_write_scanlines_rgb24(&jpeg, src); break;
case V4L2_PIX_FMT_BGR24: _jpeg_write_scanlines_bgr24(&jpeg, src); break; case V4L2_PIX_FMT_BGR24:
# ifdef JCS_EXTENSIONS
_jpeg_write_scanlines_rgb24(&jpeg, src); // Use native JCS_EXT_BGR
# else
_jpeg_write_scanlines_bgr24(&jpeg, src);
# endif
break;
default: assert(0 && "Unsupported input format for CPU encoder"); return; default: assert(0 && "Unsupported input format for CPU encoder"); return;
} }
@@ -196,6 +208,7 @@ static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const
} }
} }
#ifndef JCS_EXTENSIONS
static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) { static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const us_frame_s *frame) {
uint8_t *line_buf; uint8_t *line_buf;
US_CALLOC(line_buf, frame->width * 3); US_CALLOC(line_buf, frame->width * 3);
@@ -222,6 +235,7 @@ static void _jpeg_write_scanlines_bgr24(struct jpeg_compress_struct *jpeg, const
free(line_buf); free(line_buf);
} }
#endif
#define JPEG_OUTPUT_BUFFER_SIZE ((size_t)4096) #define JPEG_OUTPUT_BUFFER_SIZE ((size_t)4096)

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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) 2005-2006 Laurent Pinchart & Michel Xhaard #
# Copyright (C) 2006 Gabriel A. Devenyi # # Copyright (C) 2006 Gabriel A. Devenyi #
# Copyright (C) 2007 Tom Stöveken # # 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 # # 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 # # 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. # # 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 # # 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 # # 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) 2005-2006 Laurent Pinchart & Michel Xhaard #
# Copyright (C) 2006 Gabriel A. Devenyi # # Copyright (C) 2006 Gabriel A. Devenyi #
# Copyright (C) 2007 Tom Stöveken # # 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 # # 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 # # 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. # # 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 # # 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 # # 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. # # 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 # # 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 # # it under the terms of the GNU General Public License as published by #

View File

@@ -1,78 +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/>. #
# #
*****************************************************************************/
#include "h264.h"
#include <stdatomic.h>
#include "../libs/types.h"
#include "../libs/tools.h"
#include "../libs/logging.h"
#include "../libs/frame.h"
#include "../libs/memsink.h"
#include "../libs/unjpeg.h"
#include "m2m.h"
us_h264_stream_s *us_h264_stream_init(us_memsink_s *sink, const char *path, uint bitrate, uint gop) {
us_h264_stream_s *h264;
US_CALLOC(h264, 1);
h264->sink = sink;
h264->tmp_src = us_frame_init();
h264->dest = us_frame_init();
atomic_init(&h264->online, false);
h264->enc = us_m2m_h264_encoder_init("H264", path, bitrate, gop);
return h264;
}
void us_h264_stream_destroy(us_h264_stream_s *h264) {
us_m2m_encoder_destroy(h264->enc);
us_frame_destroy(h264->dest);
us_frame_destroy(h264->tmp_src);
free(h264);
}
void us_h264_stream_process(us_h264_stream_s *h264, const us_frame_s *frame, bool force_key) {
if (us_is_jpeg(frame->format)) {
const ldf now_ts = us_get_now_monotonic();
US_LOG_DEBUG("H264: Input frame is JPEG; decoding ...");
if (us_unjpeg(frame, h264->tmp_src, true) < 0) {
atomic_store(&h264->online, false);
return;
}
frame = h264->tmp_src;
US_LOG_VERBOSE("H264: JPEG decoded; time=%.3Lf", us_get_now_monotonic() - now_ts);
}
if (h264->key_requested) {
US_LOG_INFO("H264: Requested keyframe by a sink client");
h264->key_requested = false;
force_key = true;
}
bool online = false;
if (!us_m2m_encoder_compress(h264->enc, frame, h264->dest, force_key)) {
online = !us_memsink_server_put(h264->sink, h264->dest, &h264->key_requested);
}
atomic_store(&h264->online, online);
}

View File

@@ -2,7 +2,7 @@
# # # #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. # # 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 # # 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 # # 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