Compare commits

...

26 Commits

Author SHA1 Message Date
Maxim Devaev
88460b72e1 Bump version: 6.54 → 6.55 2026-02-13 23:26:35 +02:00
Sergey Radionov
8c69c77481
janus: fixed compatibility with Tailscale MTU (#325) 2026-02-13 17:34:52 +02:00
Maxim Devaev
5331ae14aa Bump version: 6.53 → 6.54 2026-02-12 20:38:03 +02:00
Maxim Devaev
0127dcf018 janus: hotfix: reverted sps/pps logic for first/last packages 2026-02-12 20:36:00 +02:00
Maxim Devaev
aa58b1b002 Bump version: 6.52 → 6.53 2026-02-12 19:47:33 +02:00
Maxim Devaev
a05eab71a8 janus: reserve 50 bytes for RTP extensions 2026-02-12 19:34:39 +02:00
Maxim Devaev
e013356cf0 janus: renamed US_RTP_DATAGRAM_SIZE -> US_RTP_TOTAL_SIZE 2026-02-12 19:27:00 +02:00
Maxim Devaev
c730981827 janus: set first/last_of_frame only for non-sps/pps packets 2026-02-12 18:48:22 +02:00
Maxim Devaev
3bb1ed3ef3 openwrt package 2026-02-09 17:09:09 +02:00
Paul Donald
1cda22bfd2
spell fixes (#323) 2026-02-09 16:59:05 +02:00
Maxim Devaev
29ee20e864 Bump version: 6.51 → 6.52 2026-02-07 17:06:14 +02:00
Maxim Devaev
5e13f4cd58 using CC -dumpmachine instead of uname 2026-02-07 17:02:43 +02:00
Maxim Devaev
39c1916f61 Bump version: 6.50 → 6.51 2026-02-03 19:52:09 +02:00
Ivan Shapovalov
614e83771b
ustreamer: options: NULL-terminate the copy of argv (#322)
According to N2176 of ISO/IEC 9899:2017 §5.1.2.2.1 ¶2:

> - argv[argc] shall be a null pointer.

Possibly fixes openwrt/packages#28472.
2026-02-03 19:41:40 +02:00
Maxim Devaev
15a9e28ac6 spelling fix 2026-02-03 10:59:26 +02:00
Maxim Devaev
a1ae02de5d janus: refactored sdp logic 2026-01-31 16:45:26 +02:00
Maxim Devaev
214708549d Bump version: 6.49 → 6.50 2026-01-30 16:21:30 +02:00
Maxim Devaev
1be4521664 Issue #321: Fixed compilation error on FreeBSD 2026-01-30 12:51:25 +02:00
Maxim Devaev
94752dde75 Bump version: 6.48 → 6.49 2026-01-28 15:14:30 +02:00
Maxim Devaev
b933b7b407 Bump version: 6.47 → 6.48 2026-01-28 14:17:18 +02:00
Maxim Devaev
61f44b5f97 janus: don't send rtp extensions with each packet 2026-01-28 12:06:37 +02:00
Maxim Devaev
8fef0408b6 janus: time functions refactored 2026-01-28 11:05:50 +02:00
Maxim Devaev
62028be064 janus: rtpv: mark all extensions as sendonly 2026-01-28 10:57:43 +02:00
Sergey Radionov
3b7592bb31
Janus: "Absolute Capture Time" RTP extension added (#320)
for video.
2026-01-28 09:59:01 +02:00
Maxim Devaev
8adca998e9 janus: fixed sdp for firefox 2026-01-28 08:50:53 +02:00
Maxim Devaev
6ac5a5f065 refactoring 2026-01-28 08:49:41 +02:00
54 changed files with 409 additions and 288 deletions

View File

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

View File

@ -35,13 +35,14 @@ If you're going to live-stream from your backyard webcam and need to control it,
# Installation # Installation
## Building ## Building
You need to download the µStreamer onto your system and build it from the sources. You need to download the µStreamer onto your system and build it from the sources, or use a package:
* AUR has a package for Arch Linux: https://aur.archlinux.org/packages/ustreamer. * Arch Linux: https://aur.archlinux.org/packages/ustreamer
* Fedora: https://src.fedoraproject.org/rpms/ustreamer. * Fedora: https://src.fedoraproject.org/rpms/ustreamer
* Ubuntu: https://packages.ubuntu.com/jammy/ustreamer. * Ubuntu: https://packages.ubuntu.com/jammy/ustreamer
* Debian: https://packages.debian.org/sid/ustreamer * Debian: https://packages.debian.org/sid/ustreamer
* FreeBSD port: https://www.freshports.org/multimedia/ustreamer. * OpenWRT: https://github.com/openwrt/packages/tree/master/multimedia/ustreamer
* FreeBSD port: https://www.freshports.org/multimedia/ustreamer
### Preconditions ### Preconditions
You'll need ```make```, ```gcc```, ```pkg-config```, ```libevent``` with ```pthreads``` support, ```libjpeg9```/```libjpeg-turbo``` and ```libbsd``` (only for Linux). You'll need ```make```, ```gcc```, ```pkg-config```, ```libevent``` with ```pthreads``` support, ```libjpeg9```/```libjpeg-turbo``` and ```libbsd``` (only for Linux).

View File

@ -19,7 +19,7 @@ _BUILD = build
# ===== # =====
ifneq ($(shell sh -c 'uname 2>/dev/null || echo Unknown'),FreeBSD) ifeq ($(findstring bsd,$(shell $(CC) -dumpmachine)),)
override _LDFLAGS += -latomic override _LDFLAGS += -latomic
endif endif

View File

@ -193,18 +193,24 @@ static void *_video_or_acap_thread(void *v_client, bool video) {
}; };
janus_plugin_rtp_extensions_reset(&packet.extensions); janus_plugin_rtp_extensions_reset(&packet.extensions);
if (rtp.zero_playout_delay) { if (rtp.first_of_frame) {
// https://github.com/pikvm/pikvm/issues/784 if (rtp.zero_playout_delay) {
packet.extensions.min_delay = 0; // https://github.com/pikvm/pikvm/issues/784
packet.extensions.max_delay = 0; packet.extensions.min_delay = 0;
} else { packet.extensions.max_delay = 0;
// Эти дефолты используются в Chrome/Safari/Firefox. } else {
// Работает всё одинаково, потому что у них общая кодовая база WebRTC. // Эти дефолты используются в Chrome/Safari/Firefox.
packet.extensions.min_delay = 0; // Работает всё одинаково, потому что у них общая кодовая база WebRTC.
packet.extensions.max_delay = 1000; // == 10s, i.e. 10ms granularity packet.extensions.min_delay = 0;
packet.extensions.max_delay = 1000; // == 10s, i.e. 10ms granularity
}
} }
if (rtp.video) { if (rtp.video && rtp.first_of_frame) {
packet.extensions.abs_capture_ts = rtp.grab_ntp_ts;
}
if (rtp.video && rtp.last_of_frame) {
uint video_orient = atomic_load(&client->video_orient); uint video_orient = atomic_load(&client->video_orient);
if (video_orient != 0) { if (video_orient != 0) {
// The extension rotates the video clockwise, but want it counterclockwise. // The extension rotates the video clockwise, but want it counterclockwise.

View File

@ -22,7 +22,6 @@
#include <stdatomic.h> #include <stdatomic.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
@ -56,6 +55,7 @@
#include "rtp.h" #include "rtp.h"
#include "rtpv.h" #include "rtpv.h"
#include "rtpa.h" #include "rtpa.h"
#include "sdp.h"
#include "memsinkfd.h" #include "memsinkfd.h"
#include "config.h" #include "config.h"
@ -279,7 +279,7 @@ static void *_acap_thread(void *arg) {
if (_get_acap_hz(&hz) < 0 || acap->pcm_hz != hz) { if (_get_acap_hz(&hz) < 0 || acap->pcm_hz != hz) {
goto close_acap; goto close_acap;
} }
uz size = US_RTP_DATAGRAM_SIZE - US_RTP_HEADER_SIZE; uz size = US_RTP_TOTAL_SIZE - US_RTP_HEADER_SIZE;
u8 data[size]; u8 data[size];
u64 pts; u64 pts;
const int result = us_acap_get_encoded(acap, data, &size, &pts); const int result = us_acap_get_encoded(acap, data, &size, &pts);
@ -641,31 +641,13 @@ static struct janus_plugin_result *_plugin_handle_message(
} }
{ {
char *sdp; char *const sdp = us_sdp_create(
char *const video_sdp = us_rtpv_make_sdp(_g_rtpv); _g_rtpv,
char *const audio_sdp = (with_acap ? us_rtpa_make_sdp(_g_rtpa, with_aplay) : us_strdup("")); (with_acap ? _g_rtpa : NULL),
US_ASPRINTF(sdp, (with_acap && with_aplay));
"v=0" RN
"o=- %" PRIu64 " 1 IN IP4 0.0.0.0" RN
"s=PiKVM uStreamer" RN
"t=0 0" RN
"%s%s",
us_get_now_id() >> 1,
# if JANUS_PLUGIN_API_VERSION >= 100
// Place video SDP before audio SDP so that the video and audio streams
// have predictable indices, even if audio is not available.
// See also client.c.
video_sdp, audio_sdp
# else
// For versions of Janus prior to 1.x, place the audio SDP first.
audio_sdp, video_sdp
# endif
);
json_t *const offer_jsep = json_pack("{ssss}", "type", "offer", "sdp", sdp); json_t *const offer_jsep = json_pack("{ssss}", "type", "offer", "sdp", sdp);
PUSH_STATUS("started", NULL, offer_jsep); PUSH_STATUS("started", NULL, offer_jsep);
json_decref(offer_jsep); json_decref(offer_jsep);
free(audio_sdp);
free(video_sdp);
free(sdp); free(sdp);
} }

View File

@ -25,10 +25,17 @@
#include "uslibs/types.h" #include "uslibs/types.h"
// https://stackoverflow.com/questions/47635545/why-webrtc-chose-rtp-max-packet-size-to-1200-bytes // Max RTP size for WebRTC is 1200 bytes:
#define US_RTP_DATAGRAM_SIZE 1200 // - https://stackoverflow.com/questions/47635545/why-webrtc-chose-rtp-max-packet-size-to-1200-bytes
// But(!) Tailscale has 1200 MTU. So to fit it required to substract:
// 1. possible RTP extensions (see sdp.c)
// 2. additional SRTP fields (>= 10 bytes)
// 3. UDP header (8 bytes)
// 4. IPv6 header (40 bytes)
// Finally it looks like 100 bytes for all above should be enough
#define US_RTP_TOTAL_SIZE (1200 - 100)
#define US_RTP_HEADER_SIZE 12 #define US_RTP_HEADER_SIZE 12
#define US_RTP_PAYLOAD_SIZE (US_RTP_DATAGRAM_SIZE - US_RTP_HEADER_SIZE) #define US_RTP_PAYLOAD_SIZE (US_RTP_TOTAL_SIZE - US_RTP_HEADER_SIZE)
#define US_RTP_H264_PAYLOAD 96 #define US_RTP_H264_PAYLOAD 96
#define US_RTP_OPUS_PAYLOAD 111 #define US_RTP_OPUS_PAYLOAD 111
@ -43,9 +50,13 @@ typedef struct {
u32 ssrc; u32 ssrc;
u16 seq; u16 seq;
u8 datagram[US_RTP_DATAGRAM_SIZE]; u8 datagram[US_RTP_TOTAL_SIZE];
uz used; uz used;
bool first_of_frame;
bool last_of_frame;
bool zero_playout_delay; bool zero_playout_delay;
u64 grab_ntp_ts;
} us_rtp_s; } us_rtp_s;
typedef void (*us_rtp_callback_f)(const us_rtp_s *rtp); typedef void (*us_rtp_callback_f)(const us_rtp_s *rtp);

View File

@ -23,11 +23,12 @@
#include "rtpa.h" #include "rtpa.h"
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h>
#include "uslibs/types.h" #include "uslibs/types.h"
#include "uslibs/tools.h" #include "uslibs/tools.h"
#include "rtp.h"
us_rtpa_s *us_rtpa_init(us_rtp_callback_f callback) { us_rtpa_s *us_rtpa_init(us_rtp_callback_f callback) {
us_rtpa_s *rtpa; us_rtpa_s *rtpa;
@ -43,32 +44,8 @@ void us_rtpa_destroy(us_rtpa_s *rtpa) {
free(rtpa); free(rtpa);
} }
char *us_rtpa_make_sdp(us_rtpa_s *rtpa, bool mic) {
const uint pl = rtpa->rtp->payload;
char *sdp;
US_ASPRINTF(sdp,
"m=audio 1 RTP/SAVPF %u" RN
"c=IN IP4 0.0.0.0" RN
"a=rtpmap:%u OPUS/%u/%u" RN
"a=fmtp:%u sprop-stereo=1" RN // useinbandfec=1
"a=rtcp-fb:%u nack" RN
"a=rtcp-fb:%u nack pli" RN
"a=rtcp-fb:%u goog-remb" RN
"a=mid:a" RN
"a=msid:audio a" RN
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
"a=%s" RN,
pl, pl,
US_RTP_OPUS_HZ, US_RTP_OPUS_CH,
pl, pl, pl, pl,
rtpa->rtp->ssrc,
(mic ? "sendrecv" : "sendonly")
);
return sdp;
}
void us_rtpa_wrap(us_rtpa_s *rtpa, const u8 *data, uz size, u32 pts) { void us_rtpa_wrap(us_rtpa_s *rtpa, const u8 *data, uz size, u32 pts) {
if (size + US_RTP_HEADER_SIZE <= US_RTP_DATAGRAM_SIZE) { if (size + US_RTP_HEADER_SIZE <= US_RTP_TOTAL_SIZE) {
us_rtp_write_header(rtpa->rtp, pts, false); us_rtp_write_header(rtpa->rtp, pts, false);
memcpy(rtpa->rtp->datagram + US_RTP_HEADER_SIZE, data, size); memcpy(rtpa->rtp->datagram + US_RTP_HEADER_SIZE, data, size);
rtpa->rtp->used = size + US_RTP_HEADER_SIZE; rtpa->rtp->used = size + US_RTP_HEADER_SIZE;

View File

@ -36,5 +36,4 @@ typedef struct {
us_rtpa_s *us_rtpa_init(us_rtp_callback_f callback); us_rtpa_s *us_rtpa_init(us_rtp_callback_f callback);
void us_rtpa_destroy(us_rtpa_s *rtpa); void us_rtpa_destroy(us_rtpa_s *rtpa);
char *us_rtpa_make_sdp(us_rtpa_s *rtpa, bool mic);
void us_rtpa_wrap(us_rtpa_s *rtpa, const u8 *data, uz size, u32 pts); void us_rtpa_wrap(us_rtpa_s *rtpa, const u8 *data, uz size, u32 pts);

View File

@ -35,6 +35,8 @@
#include "uslibs/tools.h" #include "uslibs/tools.h"
#include "uslibs/frame.h" #include "uslibs/frame.h"
#include "rtp.h"
void _rtpv_process_nalu(us_rtpv_s *rtpv, const u8 *data, uz size, u32 pts, bool marked); void _rtpv_process_nalu(us_rtpv_s *rtpv, const u8 *data, uz size, u32 pts, bool marked);
@ -55,33 +57,6 @@ void us_rtpv_destroy(us_rtpv_s *rtpv) {
free(rtpv); free(rtpv);
} }
char *us_rtpv_make_sdp(us_rtpv_s *rtpv) {
// https://tools.ietf.org/html/rfc6184
// https://github.com/meetecho/janus-gateway/issues/2443
const uint pl = rtpv->rtp->payload;
char *sdp;
US_ASPRINTF(sdp,
"m=video 1 RTP/SAVPF %u" RN
"c=IN IP4 0.0.0.0" RN
"a=rtpmap:%u H264/90000" RN
"a=fmtp:%u profile-level-id=42E01F" RN
"a=fmtp:%u packetization-mode=1" RN
"a=rtcp-fb:%u nack" RN
"a=rtcp-fb:%u nack pli" RN
"a=rtcp-fb:%u goog-remb" RN
"a=mid:v" RN
"a=msid:video v" RN
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
"a=extmap:1 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay" RN
"a=extmap:2 urn:3gpp:video-orientation" RN
"a=sendonly" RN,
pl, pl, pl, pl,
pl, pl, pl,
rtpv->rtp->ssrc
);
return sdp;
}
#define _PRE 3 // Annex B prefix length #define _PRE 3 // Annex B prefix length
void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame, bool zero_playout_delay) { void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame, bool zero_playout_delay) {
@ -90,7 +65,10 @@ void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame, bool zero_playout_de
assert(frame->format == V4L2_PIX_FMT_H264); assert(frame->format == V4L2_PIX_FMT_H264);
rtpv->rtp->first_of_frame = true;
rtpv->rtp->last_of_frame = false;
rtpv->rtp->zero_playout_delay = zero_playout_delay; rtpv->rtp->zero_playout_delay = zero_playout_delay;
rtpv->rtp->grab_ntp_ts = us_get_now_ntp() - us_ld_to_ntp(us_get_now_monotonic() - frame->grab_begin_ts);
const u32 pts = us_get_now_monotonic_u64() * 9 / 100; // PTS units are in 90 kHz const u32 pts = us_get_now_monotonic_u64() * 9 / 100; // PTS units are in 90 kHz
sz last_offset = -_PRE; sz last_offset = -_PRE;
@ -127,11 +105,30 @@ void _rtpv_process_nalu(us_rtpv_s *rtpv, const u8 *data, uz size, u32 pts, bool
const uint type = data[0] & 0x1F; const uint type = data[0] & 0x1F;
u8 *dg = rtpv->rtp->datagram; u8 *dg = rtpv->rtp->datagram;
if (size + US_RTP_HEADER_SIZE <= US_RTP_DATAGRAM_SIZE) { // Set *_of_frame flags only for non-SPS/PPS packages
/*
# define CALL_FOR_SERVICE { \
const bool m_fof = rtpv->rtp->first_of_frame; \
const bool m_lof = rtpv->rtp->last_of_frame; \
rtpv->rtp->first_of_frame = false; \
rtpv->rtp->last_of_frame = false; \
rtpv->callback(rtpv->rtp); \
rtpv->rtp->first_of_frame = m_fof; \
rtpv->rtp->last_of_frame = m_lof; \
}
*/
if (size + US_RTP_HEADER_SIZE <= US_RTP_TOTAL_SIZE) {
us_rtp_write_header(rtpv->rtp, pts, marked); us_rtp_write_header(rtpv->rtp, pts, marked);
memcpy(dg + US_RTP_HEADER_SIZE, data, size); memcpy(dg + US_RTP_HEADER_SIZE, data, size);
rtpv->rtp->used = size + US_RTP_HEADER_SIZE; rtpv->rtp->used = size + US_RTP_HEADER_SIZE;
rtpv->callback(rtpv->rtp); // if (type == 7 || type == 8) {
// CALL_FOR_SERVICE;
// } else {*/
rtpv->rtp->last_of_frame = true;
rtpv->callback(rtpv->rtp);
rtpv->rtp->first_of_frame = false;
// }
return; return;
} }
@ -142,7 +139,7 @@ void _rtpv_process_nalu(us_rtpv_s *rtpv, const u8 *data, uz size, u32 pts, bool
bool first = true; bool first = true;
while (remaining > 0) { while (remaining > 0) {
sz frag_size = US_RTP_DATAGRAM_SIZE - fu_overhead; sz frag_size = US_RTP_TOTAL_SIZE - fu_overhead;
const bool last = (remaining <= frag_size); const bool last = (remaining <= frag_size);
if (last) { if (last) {
frag_size = remaining; frag_size = remaining;
@ -163,12 +160,20 @@ void _rtpv_process_nalu(us_rtpv_s *rtpv, const u8 *data, uz size, u32 pts, bool
memcpy(dg + fu_overhead, src, frag_size); memcpy(dg + fu_overhead, src, frag_size);
rtpv->rtp->used = fu_overhead + frag_size; rtpv->rtp->used = fu_overhead + frag_size;
rtpv->callback(rtpv->rtp); // if (type == 7 || type == 8) {
// CALL_FOR_SERVICE;
// } else {
rtpv->rtp->last_of_frame = last;
rtpv->callback(rtpv->rtp);
rtpv->rtp->first_of_frame = false;
// }
src += frag_size; src += frag_size;
remaining -= frag_size; remaining -= frag_size;
first = false; first = false;
} }
# undef CALL_FOR_SERVICE
} }
static sz _find_annexb(const u8 *data, uz size) { static sz _find_annexb(const u8 *data, uz size) {

View File

@ -37,5 +37,4 @@ typedef struct {
us_rtpv_s *us_rtpv_init(us_rtp_callback_f callback); us_rtpv_s *us_rtpv_init(us_rtp_callback_f callback);
void us_rtpv_destroy(us_rtpv_s *rtpv); void us_rtpv_destroy(us_rtpv_s *rtpv);
char *us_rtpv_make_sdp(us_rtpv_s *rtpv);
void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame, bool zero_playout_delay); void us_rtpv_wrap(us_rtpv_s *rtpv, const us_frame_s *frame, bool zero_playout_delay);

110
janus/src/sdp.c Normal file
View File

@ -0,0 +1,110 @@
/*****************************************************************************
# #
# 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 "sdp.h"
#include <inttypes.h>
#include <janus/plugins/plugin.h>
#include "uslibs/types.h"
#include "uslibs/tools.h"
#include "rtp.h"
#include "rtpv.h"
#include "rtpa.h"
char *us_sdp_create(us_rtpv_s *rtpv, us_rtpa_s *rtpa, bool mic) {
char *video_sdp;
{
// https://tools.ietf.org/html/rfc6184
// https://github.com/meetecho/janus-gateway/issues/2443
const uint pl = rtpv->rtp->payload;
US_ASPRINTF(
video_sdp,
"m=video 1 RTP/SAVPF %u" RN
"c=IN IP4 0.0.0.0" RN
"a=rtpmap:%u H264/90000" RN
"a=fmtp:%u profile-level-id=42E01F;packetization-mode=1" RN
"a=rtcp-fb:%u nack" RN
"a=rtcp-fb:%u nack pli" RN
"a=rtcp-fb:%u goog-remb" RN
"a=mid:v" RN
"a=msid:video v" RN
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
"a=extmap:1/sendonly urn:3gpp:video-orientation" RN
"a=extmap:2/sendonly http://www.webrtc.org/experiments/rtp-hdrext/playout-delay" RN
"a=extmap:3/sendonly http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time" RN
"a=sendonly" RN,
pl, pl, pl, pl, pl, pl,
rtpv->rtp->ssrc);
}
char *audio_sdp;
if (rtpa == NULL) {
audio_sdp = us_strdup("");
} else {
const uint pl = rtpa->rtp->payload;
US_ASPRINTF(
audio_sdp,
"m=audio 1 RTP/SAVPF %u" RN
"c=IN IP4 0.0.0.0" RN
"a=rtpmap:%u OPUS/%u/%u" RN
"a=fmtp:%u sprop-stereo=1" RN // useinbandfec=1
"a=rtcp-fb:%u nack" RN
"a=rtcp-fb:%u nack pli" RN
"a=rtcp-fb:%u goog-remb" RN
"a=mid:a" RN
"a=msid:audio a" RN
"a=ssrc:%" PRIu32 " cname:ustreamer" RN
"a=%s" RN,
pl, pl,
US_RTP_OPUS_HZ, US_RTP_OPUS_CH,
pl, pl, pl, pl,
rtpa->rtp->ssrc,
(mic ? "sendrecv" : "sendonly"));
}
char *sdp;
US_ASPRINTF(sdp,
"v=0" RN
"o=- %" PRIu64 " 1 IN IP4 0.0.0.0" RN
"s=PiKVM uStreamer" RN
"t=0 0" RN
"%s%s",
us_get_now_id() >> 1,
# if JANUS_PLUGIN_API_VERSION >= 100
// Place video SDP before audio SDP so that the video and audio streams
// have predictable indices, even if audio is not available.
// See also client.c.
video_sdp, audio_sdp
# else
// For versions of Janus prior to 1.x, place the audio SDP first.
audio_sdp, video_sdp
# endif
);
free(audio_sdp);
free(video_sdp);
return sdp;
}

31
janus/src/sdp.h Normal file
View File

@ -0,0 +1,31 @@
/*****************************************************************************
# #
# 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
#include "uslibs/types.h"
#include "rtpv.h"
#include "rtpa.h"
char *us_sdp_create(us_rtpv_s *rtpv, us_rtpa_s *rtpa, bool mic);

View File

@ -15,8 +15,6 @@ commands = cppcheck \
--quiet \ --quiet \
--check-level=exhaustive \ --check-level=exhaustive \
--enable=warning,portability,performance,style \ --enable=warning,portability,performance,style \
--suppress=assignmentInAssert \
--suppress=assertWithSideEffect \
--suppress=variableScope \ --suppress=variableScope \
--inline-suppr \ --inline-suppr \
--library=python \ --library=python \

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.47" "January 2021" .TH USTREAMER-DUMP 1 "version 6.55" "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.47" "November 2020" .TH USTREAMER 1 "version 6.55" "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
@ -23,7 +23,7 @@ For example, the recommended way of running µStreamer with TC358743-based captu
.RS .RS
\fB\-\-format=uyvy \e\fR # Device input format \fB\-\-format=uyvy \e\fR # Device input format
.nf .nf
\fB\-\-encoder=m2m-image \e\fR # Hardware encoding with V4L2 M2M intraface \fB\-\-encoder=m2m-image \e\fR # Hardware encoding with V4L2 M2M interface
.nf .nf
\fB\-\-workers=3 \e\fR # Maximum workers for V4L2 encoder \fB\-\-workers=3 \e\fR # Maximum workers for V4L2 encoder
.nf .nf
@ -66,7 +66,7 @@ Available: MMAP, USERPTR; default: MMAP.
Desired FPS. Default: maximum possible. Desired FPS. Default: maximum possible.
.TP .TP
.BR \-z\ \fIN ", " \-\-min\-frame\-size\ \fIN .BR \-z\ \fIN ", " \-\-min\-frame\-size\ \fIN
Drop frames smaller then this limit. Useful if the device produces small\-sized garbage frames. Default: 128 bytes. Drop frames smaller than this limit. Useful if the device produces small\-sized garbage frames. Default: 128 bytes.
.TP .TP
.BR \-T ", " \-\-allow\-truncated\-frames .BR \-T ", " \-\-allow\-truncated\-frames
Allows to handle truncated frames. Useful if the device produces incorrect but still acceptable frames. Default: disabled. Allows to handle truncated frames. Useful if the device produces incorrect but still acceptable frames. Default: disabled.
@ -78,7 +78,7 @@ Suppress repetitive signal source errors. Default: disabled.
Enable DV-timings querying and events processing to automatic resolution change. Default: disabled. Enable DV-timings querying and events processing to automatic resolution change. Default: disabled.
.TP .TP
.BR \-b\ \fIN ", " \-\-buffers\ \fIN .BR \-b\ \fIN ", " \-\-buffers\ \fIN
The number of buffers to receive data from the device. Each buffer may processed using an independent thread. The number of buffers to receive data from the device. Each buffer may be processed using an independent thread.
Default: 2 (the number of CPU cores (but not more than 4) + 1). Default: 2 (the number of CPU cores (but not more than 4) + 1).
.TP .TP
.BR \-w\ \fIN ", " \-\-workers\ \fIN .BR \-w\ \fIN ", " \-\-workers\ \fIN

View File

@ -3,7 +3,7 @@
pkgname=ustreamer pkgname=ustreamer
pkgver=6.47 pkgver=6.55
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"

View File

@ -2,11 +2,14 @@
# This is free software, licensed under the GNU General Public License v2. # This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information. # See /LICENSE for more information.
# #
# This package is just an example. For OpenWRT it is recommended to use upstream package:
# - https://github.com/openwrt/packages/tree/master/multimedia/ustreamer
#
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=ustreamer PKG_NAME:=ustreamer
PKG_VERSION:=6.47 PKG_VERSION:=6.55
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com> PKG_MAINTAINER:=Maxim Devaev <mdevaev@gmail.com>

View File

@ -34,7 +34,7 @@ def main() -> None:
flags = _find_flags() flags = _find_flags()
setup( setup(
name="ustreamer", name="ustreamer",
version="6.47", version="6.55",
description="uStreamer tools", description="uStreamer tools",
author="Maxim Devaev", author="Maxim Devaev",
author_email="mdevaev@gmail.com", author_email="mdevaev@gmail.com",

View File

@ -46,7 +46,7 @@ _OBJS = $(_USTR_SRCS:%.c=$(_BUILD)/%.o) $(_DUMP_SRCS:%.c=$(_BUILD)/%.o)
# ===== # =====
ifneq ($(shell sh -c 'uname 2>/dev/null || echo Unknown'),FreeBSD) ifeq ($(findstring bsd,$(shell $(CC) -dumpmachine)),)
override _USTR_LDFLAGS += -latomic override _USTR_LDFLAGS += -latomic
override _DUMP_LDFLAGS += -latomic override _DUMP_LDFLAGS += -latomic
override _V4P_LDFLAGS += -latomic override _V4P_LDFLAGS += -latomic
@ -78,7 +78,7 @@ endif
ifneq ($(MK_WITH_SETPROCTITLE),) ifneq ($(MK_WITH_SETPROCTITLE),)
override _CFLAGS += -DMK_WITH_SETPROCTITLE -DWITH_SETPROCTITLE override _CFLAGS += -DMK_WITH_SETPROCTITLE -DWITH_SETPROCTITLE
ifeq ($(shell uname -s | tr A-Z a-z),linux) ifneq ($(findstring linux,$(shell $(CC) -dumpmachine)),)
override _USTR_LDFLAGS += -lbsd override _USTR_LDFLAGS += -lbsd
endif endif
endif endif

View File

@ -28,7 +28,6 @@
#include <float.h> #include <float.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include "../libs/const.h" #include "../libs/const.h"
#include "../libs/errors.h" #include "../libs/errors.h"

View File

@ -22,14 +22,14 @@
#pragma once #pragma once
#include <assert.h> #include "tools.h"
#define US_ARRAY_LEN(x_array) (sizeof(x_array) / sizeof((x_array)[0])) #define US_ARRAY_LEN(x_array) (sizeof(x_array) / sizeof((x_array)[0]))
#define US_ARRAY_ITERATE(x_array, x_start, x_item_ptr, ...) { \ #define US_ARRAY_ITERATE(x_array, x_start, x_item_ptr, ...) { \
const int m_len = US_ARRAY_LEN(x_array); \ const int m_len = US_ARRAY_LEN(x_array); \
assert(x_start <= m_len); \ US_A(x_start <= m_len); \
for (int m_i = x_start; m_i < m_len; ++m_i) { \ for (int m_i = x_start; m_i < m_len; ++m_i) { \
__typeof__((x_array)[0]) *const x_item_ptr = &x_array[m_i]; \ __typeof__((x_array)[0]) *const x_item_ptr = &x_array[m_i]; \
__VA_ARGS__ \ __VA_ARGS__ \

View File

@ -30,7 +30,6 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -471,7 +470,7 @@ int us_capture_hwbuf_grab(us_capture_s *cap, us_capture_hwbuf_s **hw) {
} }
int us_capture_hwbuf_release(const us_capture_s *cap, us_capture_hwbuf_s *hw) { int us_capture_hwbuf_release(const us_capture_s *cap, us_capture_hwbuf_s *hw) {
assert(atomic_load(&hw->refs) == 0); US_A(atomic_load(&hw->refs) == 0);
const uint i = hw->buf.index; const uint i = hw->buf.index;
_LOG_DEBUG("Releasing HW buffer=%u ...", i); _LOG_DEBUG("Releasing HW buffer=%u ...", i);
if (us_xioctl(cap->run->fd, VIDIOC_QBUF, &hw->buf) < 0) { if (us_xioctl(cap->run->fd, VIDIOC_QBUF, &hw->buf) < 0) {
@ -556,7 +555,7 @@ static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer
struct v4l2_plane *dest_planes = dest->m.planes; struct v4l2_plane *dest_planes = dest->m.planes;
memcpy(dest, src, sizeof(struct v4l2_buffer)); memcpy(dest, src, sizeof(struct v4l2_buffer));
if (src->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (src->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
assert(dest_planes); US_A(dest_planes);
dest->m.planes = dest_planes; dest->m.planes = dest_planes;
memcpy(dest->m.planes, src->m.planes, sizeof(struct v4l2_plane) * VIDEO_MAX_PLANES); memcpy(dest->m.planes, src->m.planes, sizeof(struct v4l2_plane) * VIDEO_MAX_PLANES);
} }
@ -911,7 +910,7 @@ static int _capture_open_io_method(us_capture_s *cap) {
switch (cap->io_method) { switch (cap->io_method) {
case V4L2_MEMORY_MMAP: return _capture_open_io_method_mmap(cap); case V4L2_MEMORY_MMAP: return _capture_open_io_method_mmap(cap);
case V4L2_MEMORY_USERPTR: return _capture_open_io_method_userptr(cap); case V4L2_MEMORY_USERPTR: return _capture_open_io_method_userptr(cap);
default: assert(0 && "Unsupported IO method"); default: US_RAISE("Unsupported IO method");
} }
return -1; return -1;
} }
@ -972,7 +971,7 @@ static int _capture_open_io_method_mmap(us_capture_s *cap) {
_LOG_PERROR("Can't map device buffer=%u", run->n_bufs); _LOG_PERROR("Can't map device buffer=%u", run->n_bufs);
return -1; return -1;
} }
assert(hw->raw.data != NULL); US_A(hw->raw.data != NULL);
hw->raw.allocated = buf_size; hw->raw.allocated = buf_size;
if (run->capture_mplane) { if (run->capture_mplane) {
@ -1014,7 +1013,7 @@ static int _capture_open_io_method_userptr(us_capture_s *cap) {
for (run->n_bufs = 0; run->n_bufs < req.count; ++run->n_bufs) { for (run->n_bufs = 0; run->n_bufs < req.count; ++run->n_bufs) {
us_capture_hwbuf_s *hw = &run->bufs[run->n_bufs]; us_capture_hwbuf_s *hw = &run->bufs[run->n_bufs];
assert((hw->raw.data = aligned_alloc(page_size, buf_size)) != NULL); US_A((hw->raw.data = aligned_alloc(page_size, buf_size)) != NULL);
memset(hw->raw.data, 0, buf_size); memset(hw->raw.data, 0, buf_size);
hw->raw.allocated = buf_size; hw->raw.allocated = buf_size;
if (run->capture_mplane) { if (run->capture_mplane) {

View File

@ -26,7 +26,7 @@
#define US_VERSION_MAJOR 6 #define US_VERSION_MAJOR 6
#define US_VERSION_MINOR 47 #define US_VERSION_MINOR 55
#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

@ -99,7 +99,7 @@ void us_drm_destroy(us_drm_s *drm) {
int us_drm_open(us_drm_s *drm, const us_capture_s *cap) { 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); US_A(run->fd < 0);
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
@ -200,7 +200,7 @@ void us_drm_close(us_drm_s *drm) {
if (run->exposing_dma_fd >= 0) { if (run->exposing_dma_fd >= 0) {
// Нужно подождать, пока dma_fd не освободится, прежде чем прерывать процесс. // Нужно подождать, пока dma_fd не освободится, прежде чем прерывать процесс.
// Просто на всякий случай. // Просто на всякий случай.
assert(run->fd >= 0); US_A(run->fd >= 0);
us_drm_wait_for_vsync(drm); us_drm_wait_for_vsync(drm);
run->exposing_dma_fd = -1; run->exposing_dma_fd = -1;
} }
@ -258,8 +258,8 @@ void us_drm_close(us_drm_s *drm) {
int us_drm_ensure_no_signal(us_drm_s *drm) { int us_drm_ensure_no_signal(us_drm_s *drm) {
us_drm_runtime_s *const run = drm->run; us_drm_runtime_s *const run = drm->run;
assert(run->fd >= 0); US_A(run->fd >= 0);
assert(run->opened > 0); US_A(run->opened > 0);
const ldf now_ts = us_get_now_monotonic(); const ldf now_ts = us_get_now_monotonic();
if (run->blank_at_ts == 0) { if (run->blank_at_ts == 0) {
@ -284,7 +284,7 @@ int us_drm_ensure_no_signal(us_drm_s *drm) {
} }
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); US_A(drm->run->fd >= 0);
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
case 0: break; case 0: break;
case US_ERROR_NO_DEVICE: return 0; // Unplugged, nice case US_ERROR_NO_DEVICE: return 0; // Unplugged, nice
@ -300,7 +300,7 @@ 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) {
us_drm_runtime_s *const run = drm->run; us_drm_runtime_s *const run = drm->run;
assert(run->fd >= 0); US_A(run->fd >= 0);
run->blank_at_ts = 0; run->blank_at_ts = 0;
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
@ -355,8 +355,8 @@ static void _drm_vsync_callback(int fd, uint n_frame, uint sec, uint usec, void
int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_capture_s *cap) { 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); US_A(run->fd >= 0);
assert(run->opened > 0); US_A(run->opened > 0);
run->blank_at_ts = 0; run->blank_at_ts = 0;
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
@ -369,7 +369,7 @@ int us_drm_expose_stub(us_drm_s *drm, us_drm_stub_e stub, const us_capture_s *ca
# 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(cap != NULL); US_A(cap != NULL);
char msg[1024]; char msg[1024];
US_SNPRINTF(msg, 1023, US_SNPRINTF(msg, 1023,
"=== PiKVM ===" "=== PiKVM ==="
@ -420,8 +420,8 @@ 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); US_A(run->fd >= 0);
assert(run->opened == 0); US_A(run->opened == 0);
run->blank_at_ts = 0; run->blank_at_ts = 0;
switch (_drm_check_status(drm)) { switch (_drm_check_status(drm)) {
@ -706,8 +706,8 @@ static drmModeModeInfo *_find_best_mode(drmModeConnector *conn, uint width, uint
if (best == NULL) { if (best == NULL) {
best = (conn->count_modes > 0 ? &conn->modes[0] : NULL); best = (conn->count_modes > 0 ? &conn->modes[0] : NULL);
} }
assert(best == NULL || best->hdisplay > 0); US_A(best == NULL || best->hdisplay > 0);
assert(best == NULL || best->vdisplay > 0); US_A(best == NULL || best->vdisplay > 0);
return best; return best;
} }

View File

@ -56,9 +56,9 @@ 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) { void us_fpsi_update(us_fpsi_s *fpsi, bool bump, const us_fpsi_meta_s *meta) {
if (meta != NULL) { if (meta != NULL) {
assert(fpsi->with_meta); US_A(fpsi->with_meta);
} else { } else {
assert(!fpsi->with_meta); US_A(!fpsi->with_meta);
} }
const sll now_ts = us_floor_ms(us_get_now_monotonic()); const sll now_ts = us_floor_ms(us_get_now_monotonic());
@ -68,7 +68,7 @@ void us_fpsi_update(us_fpsi_s *fpsi, bool bump, const us_fpsi_meta_s *meta) {
// Fast mutex-less store method // Fast mutex-less store method
ull state = (ull)fpsi->accum & 0xFFFF; ull state = (ull)fpsi->accum & 0xFFFF;
if (fpsi->with_meta) { if (fpsi->with_meta) {
assert(meta != NULL); US_A(meta != NULL);
state |= (ull)(meta->width & 0xFFFF) << 16; state |= (ull)(meta->width & 0xFFFF) << 16;
state |= (ull)(meta->height & 0xFFFF) << 32; state |= (ull)(meta->height & 0xFFFF) << 32;
state |= (ull)(meta->online ? 1 : 0) << 48; state |= (ull)(meta->online ? 1 : 0) << 48;
@ -84,7 +84,7 @@ 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) { uint us_fpsi_get(us_fpsi_s *fpsi, us_fpsi_meta_s *meta) {
if (meta != NULL) { if (meta != NULL) {
assert(fpsi->with_meta); US_A(fpsi->with_meta);
} }
// Между чтением инфы и времени может быть гонка, // Между чтением инфы и времени может быть гонка,

View File

@ -25,7 +25,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
@ -107,7 +106,7 @@ uint us_frame_get_padding(const us_frame_s *frame) {
break; break;
default: default:
assert(0 && "Unknown format"); US_RAISE("Unknown format");
} }
if (bytes_per_pixel > 0 && frame->stride > frame->width) { if (bytes_per_pixel > 0 && frame->stride > frame->width) {
return (frame->stride - frame->width * bytes_per_pixel); return (frame->stride - frame->width * bytes_per_pixel);
@ -120,7 +119,7 @@ bool us_is_jpeg(uint format) {
} }
const char *us_fourcc_to_string(uint format, char *buf, uz size) { const char *us_fourcc_to_string(uint format, char *buf, uz size) {
assert(size >= 8); US_A(size >= 8);
buf[0] = format & 0x7F; buf[0] = format & 0x7F;
buf[1] = (format >> 8) & 0x7F; buf[1] = (format >> 8) & 0x7F;
buf[2] = (format >> 16) & 0x7F; buf[2] = (format >> 16) & 0x7F;

View File

@ -84,7 +84,7 @@ typedef struct {
static inline void us_frame_encoding_begin(const us_frame_s *src, us_frame_s *dest, uint format) { static inline void us_frame_encoding_begin(const us_frame_s *src, us_frame_s *dest, uint format) {
assert(src->used > 0); US_A(src->used > 0);
US_FRAME_COPY_META(src, dest); US_FRAME_COPY_META(src, dest);
dest->encode_begin_ts = us_get_now_monotonic(); dest->encode_begin_ts = us_get_now_monotonic();
dest->format = format; dest->format = format;
@ -93,7 +93,7 @@ static inline void us_frame_encoding_begin(const us_frame_s *src, us_frame_s *de
} }
static inline void us_frame_encoding_end(us_frame_s *dest) { static inline void us_frame_encoding_end(us_frame_s *dest) {
assert(dest->used > 0); US_A(dest->used > 0);
dest->encode_end_ts = us_get_now_monotonic(); dest->encode_end_ts = us_get_now_monotonic();
} }

View File

@ -84,8 +84,8 @@ To access the nth pixel in a row, right-shift by n.
*/ */
void us_frametext_draw(us_frametext_s *ft, const char *text, uint width, uint height) { void us_frametext_draw(us_frametext_s *ft, const char *text, uint width, uint height) {
assert(width > 0); US_A(width > 0);
assert(height > 0); US_A(height > 0);
us_frame_s *const frame = ft->frame; us_frame_s *const frame = ft->frame;

View File

@ -22,7 +22,7 @@
#pragma once #pragma once
#include <assert.h> #include "tools.h"
#define US_LIST_DECLARE \ #define US_LIST_DECLARE \
@ -71,6 +71,6 @@
#define US_LIST_REMOVE_C(x_first, x_item, x_count) { \ #define US_LIST_REMOVE_C(x_first, x_item, x_count) { \
US_LIST_REMOVE(x_first, x_item); \ US_LIST_REMOVE(x_first, x_item); \
assert((x_count) >= 1); \ US_A((x_count) >= 1); \
--(x_count); \ --(x_count); \
} }

View File

@ -28,7 +28,6 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <assert.h>
#include <pthread.h> #include <pthread.h>

View File

@ -26,7 +26,6 @@
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -110,7 +109,7 @@ bool us_memsink_server_check(us_memsink_s *sink, const us_frame_s *frame) {
// Если frame == NULL, то только проверяем наличие клиентов // Если frame == NULL, то только проверяем наличие клиентов
// или необходимость инициализировать память. // или необходимость инициализировать память.
assert(sink->server); US_A(sink->server);
if (sink->mem->magic != US_MEMSINK_MAGIC || sink->mem->version != US_MEMSINK_VERSION) { if (sink->mem->magic != US_MEMSINK_MAGIC || sink->mem->version != US_MEMSINK_VERSION) {
// Если регион памяти не был инициализирован, то нужно что-то туда положить. // Если регион памяти не был инициализирован, то нужно что-то туда положить.
@ -162,7 +161,7 @@ bool us_memsink_server_check(us_memsink_s *sink, const us_frame_s *frame) {
} }
int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key_requested) { int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key_requested) {
assert(sink->server); US_A(sink->server);
const ldf now = us_get_now_monotonic(); const ldf now = us_get_now_monotonic();
@ -210,7 +209,7 @@ int us_memsink_server_put(us_memsink_s *sink, const us_frame_s *frame, bool *key
} }
int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_requested, bool key_required) { int us_memsink_client_get(us_memsink_s *sink, us_frame_s *frame, bool *key_requested, bool key_required) {
assert(!sink->server); // Client only US_A(!sink->server); // Client only
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) {

View File

@ -24,11 +24,11 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <assert.h>
#include <sys/mman.h> #include <sys/mman.h>
#include "types.h" #include "types.h"
#include "tools.h"
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) { us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) {
@ -40,12 +40,12 @@ us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) {
if (mem == MAP_FAILED) { if (mem == MAP_FAILED) {
return NULL; return NULL;
} }
assert(mem != NULL); US_A(mem != NULL);
return mem; return mem;
} }
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size) { int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size) {
assert(mem != NULL); US_A(mem != NULL);
return munmap(mem, sizeof(us_memsink_shared_s) + data_size); return munmap(mem, sizeof(us_memsink_shared_s) + data_size);
} }

View File

@ -25,15 +25,15 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <getopt.h> #include <getopt.h>
#include <assert.h>
#include "types.h" #include "types.h"
#include "tools.h"
void us_build_short_options(const struct option opts[], char *short_opts, uz size) { void us_build_short_options(const struct option opts[], char *short_opts, uz size) {
memset(short_opts, 0, size); memset(short_opts, 0, size);
for (uint short_i = 0, opt_i = 0; opts[opt_i].name != NULL; ++opt_i) { for (uint short_i = 0, opt_i = 0; opts[opt_i].name != NULL; ++opt_i) {
assert(short_i < size - 3); US_A(short_i < size - 3);
if (isalpha(opts[opt_i].val)) { if (isalpha(opts[opt_i].val)) {
short_opts[short_i] = opts[opt_i].val; short_opts[short_i] = opts[opt_i].val;
++short_i; ++short_i;

View File

@ -24,7 +24,6 @@
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <assert.h>
#include <pthread.h> #include <pthread.h>
@ -41,11 +40,11 @@ us_queue_s *us_queue_init(uint capacity) {
US_MUTEX_INIT(q->mutex); US_MUTEX_INIT(q->mutex);
pthread_condattr_t attrs; pthread_condattr_t attrs;
assert(!pthread_condattr_init(&attrs)); US_A(!pthread_condattr_init(&attrs));
assert(!pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC)); US_A(!pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC));
assert(!pthread_cond_init(&q->full_cond, &attrs)); US_A(!pthread_cond_init(&q->full_cond, &attrs));
assert(!pthread_cond_init(&q->empty_cond, &attrs)); US_A(!pthread_cond_init(&q->empty_cond, &attrs));
assert(!pthread_condattr_destroy(&attrs)); US_A(!pthread_condattr_destroy(&attrs));
return q; return q;
} }
@ -59,7 +58,7 @@ void us_queue_destroy(us_queue_s *q) {
#define _WAIT_OR_UNLOCK(x_var, x_cond) { \ #define _WAIT_OR_UNLOCK(x_var, x_cond) { \
struct timespec m_ts; \ struct timespec m_ts; \
assert(!clock_gettime(CLOCK_MONOTONIC, &m_ts)); \ US_A(!clock_gettime(CLOCK_MONOTONIC, &m_ts)); \
us_ld_to_timespec(us_timespec_to_ld(&m_ts) + timeout, &m_ts); \ us_ld_to_timespec(us_timespec_to_ld(&m_ts) + timeout, &m_ts); \
while (x_var) { \ while (x_var) { \
const int err = pthread_cond_timedwait(&(x_cond), &q->mutex, &m_ts); \ const int err = pthread_cond_timedwait(&(x_cond), &q->mutex, &m_ts); \
@ -67,7 +66,7 @@ void us_queue_destroy(us_queue_s *q) {
US_MUTEX_UNLOCK(q->mutex); \ US_MUTEX_UNLOCK(q->mutex); \
return -1; \ return -1; \
} \ } \
assert(!err); \ US_A(!err); \
} \ } \
} }

View File

@ -20,8 +20,6 @@
*****************************************************************************/ *****************************************************************************/
#include <assert.h>
#include "ring.h" #include "ring.h"
#include "types.h" #include "types.h"
@ -43,7 +41,7 @@ us_ring_s *us_ring_init(uint capacity) {
ring->consumer = us_queue_init(capacity); ring->consumer = us_queue_init(capacity);
for (uint ri = 0; ri < capacity; ++ri) { for (uint ri = 0; ri < capacity; ++ri) {
ring->places[ri] = ri; // XXX: Just to avoid casting between pointer and uint ring->places[ri] = ri; // XXX: Just to avoid casting between pointer and uint
assert(!us_queue_put(ring->producer, (void*)(ring->places + ri), 0)); US_A(!us_queue_put(ring->producer, (void*)(ring->places + ri), 0));
} }
return ring; return ring;
} }
@ -82,5 +80,5 @@ int _acquire(us_ring_s *ring, us_queue_s *q, ldf timeout) {
} }
void _release(us_ring_s *ring, us_queue_s *q, uint ri) { void _release(us_ring_s *ring, us_queue_s *q, uint ri) {
assert(!us_queue_put(q, (void*)(ring->places + ri), 0)); US_A(!us_queue_put(q, (void*)(ring->places + ri), 0));
} }

View File

@ -24,7 +24,6 @@
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <assert.h>
#if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32 #if defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
# define HAS_SIGABBREV_NP # define HAS_SIGABBREV_NP
@ -58,25 +57,25 @@ char *us_signum_to_string(int signum) {
void us_install_signals_handler(us_signal_handler_f handler, bool ignore_sigpipe) { void us_install_signals_handler(us_signal_handler_f handler, bool ignore_sigpipe) {
struct sigaction sig_act = {0}; struct sigaction sig_act = {0};
assert(!sigemptyset(&sig_act.sa_mask)); US_A(!sigemptyset(&sig_act.sa_mask));
sig_act.sa_handler = handler; sig_act.sa_handler = handler;
assert(!sigaddset(&sig_act.sa_mask, SIGINT)); US_A(!sigaddset(&sig_act.sa_mask, SIGINT));
assert(!sigaddset(&sig_act.sa_mask, SIGTERM)); US_A(!sigaddset(&sig_act.sa_mask, SIGTERM));
if (!ignore_sigpipe) { if (!ignore_sigpipe) {
assert(!sigaddset(&sig_act.sa_mask, SIGPIPE)); US_A(!sigaddset(&sig_act.sa_mask, SIGPIPE));
} }
US_LOG_DEBUG("Installing SIGINT handler ..."); US_LOG_DEBUG("Installing SIGINT handler ...");
assert(!sigaction(SIGINT, &sig_act, NULL)); US_A(!sigaction(SIGINT, &sig_act, NULL));
US_LOG_DEBUG("Installing SIGTERM handler ..."); US_LOG_DEBUG("Installing SIGTERM handler ...");
assert(!sigaction(SIGTERM, &sig_act, NULL)); US_A(!sigaction(SIGTERM, &sig_act, NULL));
if (!ignore_sigpipe) { if (!ignore_sigpipe) {
US_LOG_DEBUG("Installing SIGPIPE handler ..."); US_LOG_DEBUG("Installing SIGPIPE handler ...");
assert(!sigaction(SIGPIPE, &sig_act, NULL)); US_A(!sigaction(SIGPIPE, &sig_act, NULL));
} else { } else {
US_LOG_DEBUG("Ignoring SIGPIPE ..."); US_LOG_DEBUG("Ignoring SIGPIPE ...");
assert(signal(SIGPIPE, SIG_IGN) != SIG_ERR); US_A(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
} }
} }

View File

@ -25,7 +25,6 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <assert.h>
#include <sys/syscall.h> #include <sys/syscall.h>
@ -47,8 +46,8 @@
# define US_THREAD_NAME_SIZE ((uz)16) # define US_THREAD_NAME_SIZE ((uz)16)
#endif #endif
#define US_THREAD_CREATE(x_tid, x_func, x_arg) assert(!pthread_create(&(x_tid), NULL, (x_func), (x_arg))) #define US_THREAD_CREATE(x_tid, x_func, x_arg) US_A(!pthread_create(&(x_tid), NULL, (x_func), (x_arg)))
#define US_THREAD_JOIN(x_tid) assert(!pthread_join((x_tid), NULL)) #define US_THREAD_JOIN(x_tid) US_A(!pthread_join((x_tid), NULL))
#ifdef WITH_PTHREAD_NP #ifdef WITH_PTHREAD_NP
# define US_THREAD_RENAME(x_fmt, ...) { \ # define US_THREAD_RENAME(x_fmt, ...) { \
@ -65,16 +64,16 @@
us_thread_block_signals(); \ us_thread_block_signals(); \
} }
#define US_MUTEX_INIT(x_mutex) assert(!pthread_mutex_init(&(x_mutex), NULL)) #define US_MUTEX_INIT(x_mutex) US_A(!pthread_mutex_init(&(x_mutex), NULL))
#define US_MUTEX_DESTROY(x_mutex) assert(!pthread_mutex_destroy(&(x_mutex))) #define US_MUTEX_DESTROY(x_mutex) US_A(!pthread_mutex_destroy(&(x_mutex)))
#define US_MUTEX_LOCK(x_mutex) assert(!pthread_mutex_lock(&(x_mutex))) #define US_MUTEX_LOCK(x_mutex) US_A(!pthread_mutex_lock(&(x_mutex)))
#define US_MUTEX_UNLOCK(x_mutex) assert(!pthread_mutex_unlock(&(x_mutex))) #define US_MUTEX_UNLOCK(x_mutex) US_A(!pthread_mutex_unlock(&(x_mutex)))
#define US_COND_INIT(x_cond) assert(!pthread_cond_init(&(x_cond), NULL)) #define US_COND_INIT(x_cond) US_A(!pthread_cond_init(&(x_cond), NULL))
#define US_COND_DESTROY(x_cond) assert(!pthread_cond_destroy(&(x_cond))) #define US_COND_DESTROY(x_cond) US_A(!pthread_cond_destroy(&(x_cond)))
#define US_COND_SIGNAL(x_cond) assert(!pthread_cond_signal(&(x_cond))) #define US_COND_SIGNAL(x_cond) US_A(!pthread_cond_signal(&(x_cond)))
#define US_COND_BROADCAST(x_cond) assert(!pthread_cond_broadcast(&(x_cond))) #define US_COND_BROADCAST(x_cond) US_A(!pthread_cond_broadcast(&(x_cond)))
#define US_COND_WAIT_FOR(x_var, x_cond, x_mutex) { while(!(x_var)) assert(!pthread_cond_wait(&(x_cond), &(x_mutex))); } #define US_COND_WAIT_FOR(x_var, x_cond, x_mutex) { while(!(x_var)) US_A(!pthread_cond_wait(&(x_cond), &(x_mutex))); }
#ifdef WITH_PTHREAD_NP #ifdef WITH_PTHREAD_NP
@ -114,7 +113,7 @@ INLINE void us_thread_get_name(char *name) { // Always required for logging
const pid_t tid = syscall(SYS_gettid); const pid_t tid = syscall(SYS_gettid);
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
long id; long id;
assert(!syscall(SYS_thr_self, &id)); US_A(!syscall(SYS_thr_self, &id));
const pid_t tid = 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);
@ -135,8 +134,8 @@ INLINE void us_thread_get_name(char *name) { // Always required for logging
INLINE void us_thread_block_signals(void) { INLINE void us_thread_block_signals(void) {
sigset_t mask; sigset_t mask;
assert(!sigemptyset(&mask)); US_A(!sigemptyset(&mask));
assert(!sigaddset(&mask, SIGINT)); US_A(!sigaddset(&mask, SIGINT));
assert(!sigaddset(&mask, SIGTERM)); US_A(!sigaddset(&mask, SIGTERM));
assert(!pthread_sigmask(SIG_BLOCK, &mask, NULL)); US_A(!pthread_sigmask(SIG_BLOCK, &mask, NULL));
} }

View File

@ -51,14 +51,17 @@
#define INLINE inline __attribute__((always_inline)) #define INLINE inline __attribute__((always_inline))
#define US_CALLOC(x_dest, x_nmemb) assert(((x_dest) = calloc((x_nmemb), sizeof(*(x_dest)))) != NULL) #define US_A(x_arg) { const bool m_ar = (x_arg); assert(m_ar && #x_arg); }
#define US_REALLOC(x_dest, x_nmemb) assert(((x_dest) = realloc((x_dest), (x_nmemb) * sizeof(*(x_dest)))) != NULL) #define US_RAISE(x_msg) assert(0 && x_msg)
#define US_CALLOC(x_dest, x_nmemb) US_A(((x_dest) = calloc((x_nmemb), sizeof(*(x_dest)))) != NULL)
#define US_REALLOC(x_dest, x_nmemb) US_A(((x_dest) = realloc((x_dest), (x_nmemb) * sizeof(*(x_dest)))) != NULL)
#define US_DELETE(x_dest, x_free) { if (x_dest) { x_free(x_dest); x_dest = NULL; } } #define US_DELETE(x_dest, x_free) { if (x_dest) { x_free(x_dest); x_dest = NULL; } }
#define US_CLOSE_FD(x_dest) { if (x_dest >= 0) { close(x_dest); x_dest = -1; } } #define US_CLOSE_FD(x_dest) { if (x_dest >= 0) { close(x_dest); x_dest = -1; } }
#define US_MEMSET_ZERO(x_obj) memset(&(x_obj), 0, sizeof(x_obj)) #define US_MEMSET_ZERO(x_obj) memset(&(x_obj), 0, sizeof(x_obj))
#define US_SNPRINTF(x_dest, x_size, x_fmt, ...) assert(snprintf((x_dest), (x_size), (x_fmt), ##__VA_ARGS__) > 0) #define US_SNPRINTF(x_dest, x_size, x_fmt, ...) US_A(snprintf((x_dest), (x_size), (x_fmt), ##__VA_ARGS__) > 0)
#define US_ASPRINTF(x_dest, x_fmt, ...) assert(asprintf(&(x_dest), (x_fmt), ##__VA_ARGS__) > 0) #define US_ASPRINTF(x_dest, x_fmt, ...) US_A(asprintf(&(x_dest), (x_fmt), ##__VA_ARGS__) > 0)
#define US_MIN(x_a, x_b) ({ \ #define US_MIN(x_a, x_b) ({ \
__typeof__(x_a) m_a = (x_a); \ __typeof__(x_a) m_a = (x_a); \
@ -85,7 +88,7 @@
INLINE char *us_strdup(const char *str) { INLINE char *us_strdup(const char *str) {
char *const new = strdup(str); char *const new = strdup(str);
assert(new != NULL); US_A(new != NULL);
return new; return new;
} }
@ -115,7 +118,7 @@ INLINE u32 us_triple_u32(u32 x) {
INLINE void us_get_now(clockid_t clk_id, time_t *sec, long *msec) { INLINE void us_get_now(clockid_t clk_id, time_t *sec, long *msec) {
struct timespec ts; struct timespec ts;
assert(!clock_gettime(clk_id, &ts)); US_A(!clock_gettime(clk_id, &ts));
*sec = ts.tv_sec; *sec = ts.tv_sec;
*msec = round(ts.tv_nsec / 1.0e6); *msec = round(ts.tv_nsec / 1.0e6);
@ -134,7 +137,7 @@ INLINE ldf us_get_now_monotonic(void) {
INLINE u64 us_get_now_monotonic_u64(void) { INLINE u64 us_get_now_monotonic_u64(void) {
struct timespec ts; struct timespec ts;
assert(!clock_gettime(CLOCK_MONOTONIC, &ts)); US_A(!clock_gettime(CLOCK_MONOTONIC, &ts));
return (u64)(ts.tv_nsec / 1000) + (u64)ts.tv_sec * 1000000; return (u64)(ts.tv_nsec / 1000) + (u64)ts.tv_sec * 1000000;
} }
@ -150,12 +153,6 @@ INLINE ldf us_get_now_real(void) {
return (ldf)sec + ((ldf)msec) / 1000; return (ldf)sec + ((ldf)msec) / 1000;
} }
INLINE uint us_get_cores_available(void) {
long cores_sysconf = sysconf(_SC_NPROCESSORS_ONLN);
cores_sysconf = (cores_sysconf < 0 ? 0 : cores_sysconf);
return US_MAX(US_MIN(cores_sysconf, 4), 1);
}
INLINE void us_ld_to_timespec(ldf ld, struct timespec *ts) { INLINE void us_ld_to_timespec(ldf ld, struct timespec *ts) {
ts->tv_sec = (long)ld; ts->tv_sec = (long)ld;
ts->tv_nsec = (ld - ts->tv_sec) * 1000000000L; ts->tv_nsec = (ld - ts->tv_sec) * 1000000000L;
@ -169,6 +166,28 @@ INLINE ldf us_timespec_to_ld(const struct timespec *ts) {
return ts->tv_sec + ((ldf)ts->tv_nsec) / 1000000000; return ts->tv_sec + ((ldf)ts->tv_nsec) / 1000000000;
} }
#define NTP_UNIX_TIME_DIFF 2208988800u // Difference between Unix time and NTP time in seconds (1970 - 1900)
#define NTP_TICKS_IN_SECOND 4294967296u // Ticks per second in NTP time
INLINE u64 us_get_now_ntp(void) {
struct timespec ts;
US_A(!clock_gettime(CLOCK_REALTIME, &ts));
return (((u64)ts.tv_sec + NTP_UNIX_TIME_DIFF) << 32) + ((u64)ts.tv_nsec / 1000 * NTP_TICKS_IN_SECOND) / 1000000;
}
INLINE u64 us_ld_to_ntp(ldf ld) {
return (ld > 0 ? ld * NTP_TICKS_IN_SECOND : 0);
}
#undef NTP_TICKS_IN_SECOND
#undef NTP_UNIX_TIME_DIFF
INLINE uint us_get_cores_available(void) {
long cores_sysconf = sysconf(_SC_NPROCESSORS_ONLN);
cores_sysconf = (cores_sysconf < 0 ? 0 : cores_sysconf);
return US_MAX(US_MIN(cores_sysconf, 4), 1);
}
INLINE int us_flock_timedwait_monotonic(int fd, ldf timeout) { INLINE int us_flock_timedwait_monotonic(int fd, ldf timeout) {
const ldf deadline_ts = us_get_now_monotonic() + timeout; const ldf deadline_ts = us_get_now_monotonic() + timeout;
int retval = -1; int retval = -1;

View File

@ -24,12 +24,12 @@
#include <stdio.h> #include <stdio.h>
#include <setjmp.h> #include <setjmp.h>
#include <assert.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include "types.h" #include "types.h"
#include "tools.h"
#include "logging.h" #include "logging.h"
#include "frame.h" #include "frame.h"
@ -45,7 +45,7 @@ static void _jpeg_error_handler(j_common_ptr jpeg);
int us_unjpeg(const us_frame_s *src, us_frame_s *dest, bool decode) { int us_unjpeg(const us_frame_s *src, us_frame_s *dest, bool decode) {
assert(us_is_jpeg(src->format)); US_A(us_is_jpeg(src->format));
volatile int retval = 0; volatile int retval = 0;

View File

@ -24,7 +24,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <strings.h> #include <strings.h>
#include <assert.h>
#include <pthread.h> #include <pthread.h>
@ -113,7 +112,7 @@ void us_encoder_open(us_encoder_s *enc, us_capture_s *cap) {
us_encoder_runtime_s *const run = enc->run; us_encoder_runtime_s *const run = enc->run;
us_capture_runtime_s *const cr = cap->run; us_capture_runtime_s *const cr = cap->run;
assert(run->pool == NULL); US_A(run->pool == NULL);
us_encoder_type_e type = enc->type; us_encoder_type_e type = enc->type;
uint quality = cap->jpeg_quality; uint quality = cap->jpeg_quality;
@ -176,7 +175,7 @@ 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) {
assert(enc->run->pool != NULL); US_A(enc->run->pool != NULL);
US_DELETE(enc->run->pool, us_workers_pool_destroy); US_DELETE(enc->run->pool, us_workers_pool_destroy);
} }
@ -226,7 +225,7 @@ static bool _worker_run_job(us_worker_s *wr) {
} }
} else { } else {
assert(0 && "Unknown encoder type"); US_RAISE("Unknown encoder type");
} }
US_LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%s, buffer=%u", US_LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%s, buffer=%u",

View File

@ -30,7 +30,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <assert.h>
#include <jpeglib.h> #include <jpeglib.h>
@ -140,7 +139,8 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, uint quali
_jpeg_write_scanlines_bgr24(&jpeg, src); _jpeg_write_scanlines_bgr24(&jpeg, src);
# endif # endif
break; break;
default: assert(0 && "Unsupported input format for CPU encoder"); return; default:
US_RAISE("Unsupported input format for CPU encoder");
} }
jpeg_finish_compress(&jpeg); jpeg_finish_compress(&jpeg);
@ -151,7 +151,7 @@ void us_cpu_encoder_compress(const us_frame_s *src, us_frame_s *dest, uint quali
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame) { static void _jpeg_set_dest_frame(j_compress_ptr jpeg, us_frame_s *frame) {
if (jpeg->dest == NULL) { if (jpeg->dest == NULL) {
assert((jpeg->dest = (struct jpeg_destination_mgr*)(*jpeg->mem->alloc_small)( US_A((jpeg->dest = (struct jpeg_destination_mgr*)(*jpeg->mem->alloc_small)(
(j_common_ptr) jpeg, JPOOL_PERMANENT, sizeof(_jpeg_dest_manager_s) (j_common_ptr) jpeg, JPOOL_PERMANENT, sizeof(_jpeg_dest_manager_s)
)) != NULL); )) != NULL);
} }
@ -192,8 +192,7 @@ static void _jpeg_write_scanlines_yuv(struct jpeg_compress_struct *jpeg, const u
u = data[0]; u = data[0];
v = data[2]; v = data[2];
} else { } else {
assert(0 && "Unsupported pixel format"); US_RAISE("Unsupported pixel format");
return; // Makes linter happy
} }
ptr[0] = y; ptr[0] = y;
@ -247,8 +246,7 @@ static void _jpeg_write_scanlines_yuv_planar(struct jpeg_compress_struct *jpeg,
v = chroma1_data[chroma_position]; v = chroma1_data[chroma_position];
break; break;
default: default:
assert(0 && "Unsupported pixel format"); US_RAISE("Unsupported pixel format");
return; // Makes linter happy
} }
ptr[0] = y; ptr[0] = y;
@ -371,7 +369,7 @@ static void _jpeg_init_destination(j_compress_ptr jpeg) {
_jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest; _jpeg_dest_manager_s *const dest = (_jpeg_dest_manager_s*)jpeg->dest;
// Allocate the output buffer - it will be released when done with image // Allocate the output buffer - it will be released when done with image
assert((dest->buf = (JOCTET*)(*jpeg->mem->alloc_small)( US_A((dest->buf = (JOCTET*)(*jpeg->mem->alloc_small)(
(j_common_ptr) jpeg, JPOOL_IMAGE, JPEG_OUTPUT_BUFFER_SIZE * sizeof(JOCTET) (j_common_ptr) jpeg, JPOOL_IMAGE, JPEG_OUTPUT_BUFFER_SIZE * sizeof(JOCTET)
)) != NULL); )) != NULL);

View File

@ -28,11 +28,11 @@
#include "encoder.h" #include "encoder.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include "../../../libs/types.h" #include "../../../libs/types.h"
#include "../../../libs/tools.h"
#include "../../../libs/frame.h" #include "../../../libs/frame.h"
#include "huffman.h" #include "huffman.h"
@ -43,7 +43,7 @@ static bool _is_huffman(const u8 *data);
void us_hw_encoder_compress(const us_frame_s *src, us_frame_s *dest) { void us_hw_encoder_compress(const us_frame_s *src, us_frame_s *dest) {
assert(us_is_jpeg(src->format)); US_A(us_is_jpeg(src->format));
_copy_plus_huffman(src, dest); _copy_plus_huffman(src, dest);
} }

View File

@ -52,7 +52,7 @@ static void _gpio_output_destroy(us_gpio_output_s *out);
void us_gpio_init(void) { void us_gpio_init(void) {
# ifndef HAVE_GPIOD2 # ifndef HAVE_GPIOD2
assert(us_g_gpio.chip == NULL); US_A(us_g_gpio.chip == NULL);
# endif # endif
if ( if (
us_g_gpio.prog_running.pin >= 0 us_g_gpio.prog_running.pin >= 0
@ -96,10 +96,10 @@ int us_gpio_inner_set(us_gpio_output_s *out, bool on) {
int retval = 0; int retval = 0;
# ifndef HAVE_GPIOD2 # ifndef HAVE_GPIOD2
assert(us_g_gpio.chip != NULL); US_A(us_g_gpio.chip != NULL);
# endif # endif
assert(out->line != NULL); US_A(out->line != NULL);
assert(out->on != on); // Must be checked in macro for the performance US_A(out->on != on); // Must be checked in macro for the performance
US_MUTEX_LOCK(us_g_gpio.mutex); US_MUTEX_LOCK(us_g_gpio.mutex);
# ifdef HAVE_GPIOD2 # ifdef HAVE_GPIOD2
@ -117,24 +117,24 @@ int us_gpio_inner_set(us_gpio_output_s *out, bool on) {
} }
static void _gpio_output_init(us_gpio_output_s *out, struct gpiod_chip *chip) { static void _gpio_output_init(us_gpio_output_s *out, struct gpiod_chip *chip) {
assert(out->line == NULL); US_A(out->line == NULL);
US_ASPRINTF(out->consumer, "%s::%s", us_g_gpio.consumer_prefix, out->role); US_ASPRINTF(out->consumer, "%s::%s", us_g_gpio.consumer_prefix, out->role);
if (out->pin >= 0) { if (out->pin >= 0) {
# ifdef HAVE_GPIOD2 # ifdef HAVE_GPIOD2
struct gpiod_line_settings *line_settings; struct gpiod_line_settings *line_settings;
assert(line_settings = gpiod_line_settings_new()); US_A(line_settings = gpiod_line_settings_new());
assert(!gpiod_line_settings_set_direction(line_settings, GPIOD_LINE_DIRECTION_OUTPUT)); US_A(!gpiod_line_settings_set_direction(line_settings, GPIOD_LINE_DIRECTION_OUTPUT));
assert(!gpiod_line_settings_set_output_value(line_settings, false)); US_A(!gpiod_line_settings_set_output_value(line_settings, false));
struct gpiod_line_config *line_config; struct gpiod_line_config *line_config;
assert(line_config = gpiod_line_config_new()); US_A(line_config = gpiod_line_config_new());
const unsigned offset = out->pin; const unsigned offset = out->pin;
assert(!gpiod_line_config_add_line_settings(line_config, &offset, 1, line_settings)); US_A(!gpiod_line_config_add_line_settings(line_config, &offset, 1, line_settings));
struct gpiod_request_config *req_config; struct gpiod_request_config *req_config;
assert(req_config = gpiod_request_config_new()); US_A(req_config = gpiod_request_config_new());
gpiod_request_config_set_consumer(req_config, out->consumer); gpiod_request_config_set_consumer(req_config, out->consumer);
if ((out->line = gpiod_chip_request_lines(chip, req_config, line_config)) == NULL) { if ((out->line = gpiod_chip_request_lines(chip, req_config, line_config)) == NULL) {

View File

@ -25,7 +25,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <pthread.h> #include <pthread.h>
#include <gpiod.h> #include <gpiod.h>

View File

@ -31,7 +31,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -102,12 +101,12 @@ static bool _expose_frame(us_server_s *server, const us_frame_s *frame);
#define _LOG_VERBOSE(x_msg, ...) US_LOG_VERBOSE("HTTP: " x_msg, ##__VA_ARGS__) #define _LOG_VERBOSE(x_msg, ...) US_LOG_VERBOSE("HTTP: " x_msg, ##__VA_ARGS__)
#define _LOG_DEBUG(x_msg, ...) US_LOG_DEBUG("HTTP: " x_msg, ##__VA_ARGS__) #define _LOG_DEBUG(x_msg, ...) US_LOG_DEBUG("HTTP: " x_msg, ##__VA_ARGS__)
#define _A_EVBUFFER_NEW(x_buf) assert((x_buf = evbuffer_new()) != NULL) #define _A_EVBUFFER_NEW(x_buf) US_A((x_buf = evbuffer_new()) != NULL)
#define _A_EVBUFFER_ADD(x_buf, x_data, x_size) assert(!evbuffer_add(x_buf, x_data, x_size)) #define _A_EVBUFFER_ADD(x_buf, x_data, x_size) US_A(!evbuffer_add(x_buf, x_data, x_size))
#define _A_EVBUFFER_ADD_PRINTF(x_buf, x_fmt, ...) assert(evbuffer_add_printf(x_buf, x_fmt, ##__VA_ARGS__) >= 0) #define _A_EVBUFFER_ADD_PRINTF(x_buf, x_fmt, ...) US_A(evbuffer_add_printf(x_buf, x_fmt, ##__VA_ARGS__) >= 0)
#define _A_ADD_HEADER(x_req, x_key, x_value) \ #define _A_ADD_HEADER(x_req, x_key, x_value) \
assert(!evhttp_add_header(evhttp_request_get_output_headers(x_req), x_key, x_value)) US_A(!evhttp_add_header(evhttp_request_get_output_headers(x_req), x_key, x_value))
us_server_s *us_server_init(us_stream_s *stream) { us_server_s *us_server_init(us_stream_s *stream) {
@ -135,9 +134,9 @@ us_server_s *us_server_init(us_stream_s *stream) {
server->stream = stream; server->stream = stream;
server->run = run; server->run = run;
assert(!evthread_use_pthreads()); US_A(!evthread_use_pthreads());
assert((run->base = event_base_new()) != NULL); US_A((run->base = event_base_new()) != NULL);
assert((run->http = evhttp_new(run->base)) != NULL); US_A((run->http = evhttp_new(run->base)) != NULL);
evhttp_set_allowed_methods(run->http, EVHTTP_REQ_GET|EVHTTP_REQ_HEAD|EVHTTP_REQ_OPTIONS); evhttp_set_allowed_methods(run->http, EVHTTP_REQ_GET|EVHTTP_REQ_HEAD|EVHTTP_REQ_OPTIONS);
return server; return server;
} }
@ -188,17 +187,17 @@ int us_server_listen(us_server_s *server) {
_LOG_INFO("Enabling the file server: %s", server->static_path); _LOG_INFO("Enabling the file server: %s", server->static_path);
evhttp_set_gencb(run->http, _http_callback_static, (void*)server); evhttp_set_gencb(run->http, _http_callback_static, (void*)server);
} else { } else {
assert(!evhttp_set_cb(run->http, "/", _http_callback_root, (void*)server)); US_A(!evhttp_set_cb(run->http, "/", _http_callback_root, (void*)server));
assert(!evhttp_set_cb(run->http, "/favicon.ico", _http_callback_favicon, (void*)server)); US_A(!evhttp_set_cb(run->http, "/favicon.ico", _http_callback_favicon, (void*)server));
} }
assert(!evhttp_set_cb(run->http, "/state", _http_callback_state, (void*)server)); US_A(!evhttp_set_cb(run->http, "/state", _http_callback_state, (void*)server));
assert(!evhttp_set_cb(run->http, "/snapshot", _http_callback_snapshot, (void*)server)); US_A(!evhttp_set_cb(run->http, "/snapshot", _http_callback_snapshot, (void*)server));
assert(!evhttp_set_cb(run->http, "/stream", _http_callback_stream, (void*)server)); US_A(!evhttp_set_cb(run->http, "/stream", _http_callback_stream, (void*)server));
} }
us_frame_copy(stream->run->blank->jpeg, ex->frame); us_frame_copy(stream->run->blank->jpeg, ex->frame);
assert((run->refresher = event_new(run->base, -1, 0, _http_refresher, server)) != NULL); US_A((run->refresher = event_new(run->base, -1, 0, _http_refresher, server)) != NULL);
stream->run->http->jpeg_refresher = run->refresher; stream->run->http->jpeg_refresher = run->refresher;
evhttp_set_timeout(run->http, server->timeout); evhttp_set_timeout(run->http, server->timeout);
@ -612,7 +611,7 @@ static void _http_callback_stream(struct evhttp_request *req, void *v_server) {
if (server->tcp_nodelay && run->ext_fd >= 0) { if (server->tcp_nodelay && run->ext_fd >= 0) {
_LOG_DEBUG("Setting up TCP_NODELAY to the client %s ...", client->hostport); _LOG_DEBUG("Setting up TCP_NODELAY to the client %s ...", client->hostport);
const evutil_socket_t fd = bufferevent_getfd(buf_event); const evutil_socket_t fd = bufferevent_getfd(buf_event);
assert(fd >= 0); US_A(fd >= 0);
int on = 1; int on = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) != 0) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) != 0) {
_LOG_PERROR("Can't set TCP_NODELAY to the client %s", client->hostport); _LOG_PERROR("Can't set TCP_NODELAY to the client %s", client->hostport);
@ -703,7 +702,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
ADD_ADVANCE_HEADERS; ADD_ADVANCE_HEADERS;
} }
assert(!bufferevent_write_buffer(buf_event, buf)); US_A(!bufferevent_write_buffer(buf_event, buf));
client->need_initial = false; client->need_initial = false;
} }
@ -763,7 +762,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
ADD_ADVANCE_HEADERS; ADD_ADVANCE_HEADERS;
} }
assert(!bufferevent_write_buffer(buf_event, buf)); US_A(!bufferevent_write_buffer(buf_event, buf));
evbuffer_free(buf); evbuffer_free(buf);
bufferevent_setcb(buf_event, NULL, NULL, _http_callback_stream_error, (void*)client); bufferevent_setcb(buf_event, NULL, NULL, _http_callback_stream_error, (void*)client);

View File

@ -26,7 +26,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -46,7 +45,7 @@ char *us_find_static_file_path(const char *root_path, const char *req_path) {
} }
US_CALLOC(path, strlen(root_path) + strlen(simplified_path) + 16); // + reserved for /index.html US_CALLOC(path, strlen(root_path) + strlen(simplified_path) + 16); // + reserved for /index.html
assert(sprintf(path, "%s/%s", root_path, simplified_path) > 0); US_A(sprintf(path, "%s/%s", root_path, simplified_path) > 0);
struct stat st; struct stat st;
# define LOAD_STAT { \ # define LOAD_STAT { \

View File

@ -23,7 +23,6 @@
#include "systemd.h" #include "systemd.h"
#include <unistd.h> #include <unistd.h>
#include <assert.h>
#include <event2/http.h> #include <event2/http.h>
#include <event2/util.h> #include <event2/util.h>
@ -47,7 +46,7 @@ evutil_socket_t us_evhttp_bind_systemd(struct evhttp *http) {
} }
fd = SD_LISTEN_FDS_START; fd = SD_LISTEN_FDS_START;
assert(!evutil_make_socket_nonblocking(fd)); US_A(!evutil_make_socket_nonblocking(fd));
if (evhttp_accept_socket(http, fd) < 0) { if (evhttp_accept_socket(http, fd) < 0) {
US_LOG_PERROR("HTTP: Can't evhttp_accept_socket() systemd socket"); US_LOG_PERROR("HTTP: Can't evhttp_accept_socket() systemd socket");

View File

@ -25,7 +25,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
@ -54,8 +53,8 @@ evutil_socket_t us_evhttp_bind_unix(struct evhttp *http, const char *path, bool
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
const evutil_socket_t fd = socket(AF_UNIX, SOCK_STREAM, 0); const evutil_socket_t fd = socket(AF_UNIX, SOCK_STREAM, 0);
assert(fd >= 0); US_A(fd >= 0);
assert(!evutil_make_socket_nonblocking(fd)); US_A(!evutil_make_socket_nonblocking(fd));
if (rm && unlink(path) < 0) { if (rm && unlink(path) < 0) {
if (errno != ENOENT) { if (errno != ENOENT) {
@ -99,7 +98,7 @@ char *us_evhttp_get_hostport(struct evhttp_request *req) {
const char *xff = us_evhttp_get_header(req, "X-Forwarded-For"); const char *xff = us_evhttp_get_header(req, "X-Forwarded-For");
if (xff != NULL) { if (xff != NULL) {
US_DELETE(addr, free); US_DELETE(addr, free);
assert((addr = strndup(xff, 1024)) != NULL); US_A((addr = strndup(xff, 1024)) != NULL);
for (uint i = 0; addr[i]; ++i) { for (uint i = 0; addr[i]; ++i) {
if (addr[i] == ',') { if (addr[i] == ',') {
addr[i] = '\0'; addr[i] = '\0';

View File

@ -28,7 +28,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -89,7 +88,7 @@ us_m2m_encoder_s *us_m2m_mjpeg_encoder_init(const char *name, const char *path,
double bitrate = log10(quality) * (b_max - b_min) / 2 + b_min; double bitrate = log10(quality) * (b_max - b_min) / 2 + b_min;
bitrate = step * round(bitrate / step); bitrate = step * round(bitrate / step);
bitrate *= 1000; // From Kbps bitrate *= 1000; // From Kbps
assert(bitrate > 0); US_A(bitrate > 0);
return _m2m_encoder_init(name, path, V4L2_PIX_FMT_MJPEG, bitrate, 0, 0, true, false); return _m2m_encoder_init(name, path, V4L2_PIX_FMT_MJPEG, bitrate, 0, 0, true, false);
} }
@ -417,7 +416,7 @@ static int _m2m_encoder_init_buffers(
_LOG_PERROR("Can't map %s buffer=%u", name, *n_bufs_ptr); _LOG_PERROR("Can't map %s buffer=%u", name, *n_bufs_ptr);
goto error; goto error;
} }
assert((*bufs_ptr)[*n_bufs_ptr].data != NULL); US_A((*bufs_ptr)[*n_bufs_ptr].data != NULL);
(*bufs_ptr)[*n_bufs_ptr].allocated = plane.length; (*bufs_ptr)[*n_bufs_ptr].allocated = plane.length;
_LOG_DEBUG("Queuing %s buffer=%u ...", name, *n_bufs_ptr); _LOG_DEBUG("Queuing %s buffer=%u ...", name, *n_bufs_ptr);
@ -492,7 +491,7 @@ static int _m2m_encoder_compress_raw(
) { ) {
us_m2m_encoder_runtime_s *const run = enc->run; us_m2m_encoder_runtime_s *const run = enc->run;
assert(run->ready); US_A(run->ready);
if (force_key) { if (force_key) {
struct v4l2_control ctl = {0}; struct v4l2_control ctl = {0};

View File

@ -46,10 +46,10 @@ static us_server_s *_g_server = NULL;
static void _block_thread_signals(void) { static void _block_thread_signals(void) {
sigset_t mask; sigset_t mask;
assert(!sigemptyset(&mask)); US_A(!sigemptyset(&mask));
assert(!sigaddset(&mask, SIGINT)); US_A(!sigaddset(&mask, SIGINT));
assert(!sigaddset(&mask, SIGTERM)); US_A(!sigaddset(&mask, SIGTERM));
assert(!pthread_sigmask(SIG_BLOCK, &mask, NULL)); US_A(!pthread_sigmask(SIG_BLOCK, &mask, NULL));
} }
static void *_stream_loop_thread(void *arg) { static void *_stream_loop_thread(void *arg) {
@ -77,7 +77,7 @@ static void _signal_handler(int signum) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
assert(argc >= 0); US_A(argc >= 0);
int exit_code = 0; int exit_code = 0;
US_LOGGING_INIT; US_LOGGING_INIT;

View File

@ -30,10 +30,10 @@
#include <limits.h> #include <limits.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include "../libs/types.h" #include "../libs/types.h"
#include "../libs/const.h" #include "../libs/const.h"
#include "../libs/tools.h"
#include "../libs/logging.h" #include "../libs/logging.h"
#include "../libs/process.h" #include "../libs/process.h"
#include "../libs/frame.h" #include "../libs/frame.h"
@ -300,10 +300,11 @@ us_options_s *us_options_init(uint argc, char *argv[]) {
opts->argc = argc; opts->argc = argc;
opts->argv = argv; opts->argv = argv;
US_CALLOC(opts->argv_copy, argc); US_CALLOC(opts->argv_copy, argc + 1);
for (uint i = 0; i < argc; ++i) { for (uint i = 0; i < argc; ++i) {
opts->argv_copy[i] = us_strdup(argv[i]); opts->argv_copy[i] = us_strdup(argv[i]);
} }
opts->argv_copy[argc] = NULL;
return opts; return opts;
} }
@ -358,7 +359,7 @@ int us_options_parse(
printf("Invalid height of '%s=%s': min=%u, max=%u\n", x_name, optarg, US_VIDEO_MIN_HEIGHT, US_VIDEO_MAX_HEIGHT); \ printf("Invalid height of '%s=%s': min=%u, max=%u\n", x_name, optarg, US_VIDEO_MIN_HEIGHT, US_VIDEO_MAX_HEIGHT); \
return -1; \ return -1; \
case 0: break; \ case 0: break; \
default: assert(0 && "Unknown error"); \ default: US_RAISE("Unknown error"); \
} \ } \
break; \ break; \
} }
@ -704,7 +705,7 @@ static void _help(
SAY(" Changing of this parameter may increase the performance. Or not."); SAY(" Changing of this parameter may increase the performance. Or not.");
SAY(" Available: %s; default: MMAP.\n", US_IO_METHODS_STR); SAY(" Available: %s; default: MMAP.\n", US_IO_METHODS_STR);
SAY(" -f|--desired-fps <N> ──────────────── Desired FPS. Default: maximum possible.\n"); SAY(" -f|--desired-fps <N> ──────────────── Desired FPS. Default: maximum possible.\n");
SAY(" -z|--min-frame-size <N> ───────────── Drop frames smaller then this limit. Useful if the device"); SAY(" -z|--min-frame-size <N> ───────────── Drop frames smaller than this limit. Useful if the device");
SAY(" produces small-sized garbage frames. Default: %zu bytes.\n", cap->min_frame_size); SAY(" produces small-sized garbage frames. Default: %zu bytes.\n", cap->min_frame_size);
SAY(" -T|--allow-truncated-frames ───────── Allows to handle truncated frames. Useful if the device"); SAY(" -T|--allow-truncated-frames ───────── Allows to handle truncated frames. Useful if the device");
SAY(" produces incorrect but still acceptable frames. Default: disabled.\n"); SAY(" produces incorrect but still acceptable frames. Default: disabled.\n");
@ -712,7 +713,7 @@ static void _help(
SAY(" -t|--dv-timings ───────────────────── Enable DV-timings querying and events processing"); SAY(" -t|--dv-timings ───────────────────── Enable DV-timings querying and events processing");
SAY(" to automatic resolution change. Default: disabled.\n"); SAY(" to automatic resolution change. Default: disabled.\n");
SAY(" -b|--buffers <N> ──────────────────── The number of buffers to receive data from the device."); SAY(" -b|--buffers <N> ──────────────────── The number of buffers to receive data from the device.");
SAY(" Each buffer may processed using an independent thread."); SAY(" Each buffer may be processed using an independent thread.");
SAY(" Default: %u (the number of CPU cores (but not more than 4) + 1).\n", cap->n_bufs); SAY(" Default: %u (the number of CPU cores (but not more than 4) + 1).\n", cap->n_bufs);
SAY(" -w|--workers <N> ──────────────────── The number of worker threads but not more than buffers."); SAY(" -w|--workers <N> ──────────────────── The number of worker threads but not more than buffers.");
SAY(" Default: %u (the number of CPU cores (but not more than 4)).\n", enc->n_workers); SAY(" Default: %u (the number of CPU cores (but not more than 4)).\n", enc->n_workers);

View File

@ -27,7 +27,6 @@
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <math.h> #include <math.h>
#include <pthread.h> #include <pthread.h>
@ -199,7 +198,7 @@ void us_stream_loop(us_stream_s *stream) {
CREATE_WORKER((stream->raw_sink != NULL), raw_ctx, _raw_thread, 2); CREATE_WORKER((stream->raw_sink != NULL), raw_ctx, _raw_thread, 2);
CREATE_WORKER((stream->h264_sink != NULL), h264_ctx, _h264_thread, cap->run->n_bufs); CREATE_WORKER((stream->h264_sink != NULL), h264_ctx, _h264_thread, cap->run->n_bufs);
# ifdef WITH_V4P # ifdef WITH_V4P
CREATE_WORKER((stream->drm != NULL), drm_ctx, _drm_thread, cap->run->n_bufs); // cppcheck-suppress assertWithSideEffect CREATE_WORKER((stream->drm != NULL), drm_ctx, _drm_thread, cap->run->n_bufs);
# endif # endif
# undef CREATE_WORKER # undef CREATE_WORKER
@ -528,7 +527,7 @@ static us_capture_hwbuf_s *_get_latest_hw(us_queue_s *q) {
} }
while (!us_queue_is_empty(q)) { // Берем только самый свежий кадр while (!us_queue_is_empty(q)) { // Берем только самый свежий кадр
us_capture_hwbuf_decref(hw); us_capture_hwbuf_decref(hw);
assert(!us_queue_get(q, (void**)&hw, 0)); US_A(!us_queue_get(q, (void**)&hw, 0));
} }
return hw; return hw;
} }
@ -771,7 +770,7 @@ static void _stream_check_suicide(us_stream_s *stream) {
return; return;
} }
const atomic_ullong *last_req_ts = &stream->run->http->last_req_ts; atomic_ullong *last_req_ts = &stream->run->http->last_req_ts;
const ldf now_ts = us_get_now_monotonic(); const ldf now_ts = us_get_now_monotonic();
if (_stream_has_any_clients_cached(stream)) { if (_stream_has_any_clients_cached(stream)) {

View File

@ -122,7 +122,7 @@ us_worker_s *us_workers_pool_wait(us_workers_pool_s *pool) {
found = wr; found = wr;
} }
}); });
assert(found != NULL); US_A(found != NULL);
US_LIST_REMOVE(pool->workers, found); US_LIST_REMOVE(pool->workers, found);
US_LIST_APPEND(pool->workers, found); // Перемещаем в конец списка US_LIST_APPEND(pool->workers, found); // Перемещаем в конец списка

View File

@ -28,7 +28,6 @@
#include <unistd.h> #include <unistd.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <pthread.h> #include <pthread.h>
@ -245,11 +244,11 @@ static void _main_loop(void) {
static void *_follower_thread(void *v_unix_follow) { // cppcheck-suppress constParameterCallback static void *_follower_thread(void *v_unix_follow) { // cppcheck-suppress constParameterCallback
US_THREAD_SETTLE("follower"); US_THREAD_SETTLE("follower");
const char *path = v_unix_follow; const char *path = v_unix_follow;
assert(path != NULL); US_A(path != NULL);
while (!atomic_load(&_g_stop)) { while (!atomic_load(&_g_stop)) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0); int fd = socket(AF_UNIX, SOCK_STREAM, 0);
assert(fd >= 0); US_A(fd >= 0);
struct sockaddr_un addr = {0}; struct sockaddr_un addr = {0};
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);