Compare commits

...

22 Commits
v5.5 ... v5.7

Author SHA1 Message Date
Maxim Devaev
a360f1901e Bump version: 5.6 → 5.7 2022-06-07 05:32:38 +03:00
Maxim Devaev
ed2d5f3af4 not based 2022-06-07 05:25:05 +03:00
Maxim Devaev
b935dd1fe8 refactoring 2022-06-07 05:00:35 +03:00
Maxim Devaev
6e1f60a36d get rid of ATOMIC_VAR_INIT 2022-06-07 04:58:09 +03:00
Maxim Devaev
210dfcfa4f lint fix 2022-06-07 04:51:46 +03:00
Maxim Devaev
ec10a9e3fe using c17 2022-06-07 04:48:28 +03:00
Maxim Devaev
217d146378 log fix 2022-06-07 03:01:27 +03:00
Maxim Devaev
3e2a43e2af speed up cppcheck 2022-06-07 02:54:39 +03:00
Maxim Devaev
2e0a19c1cb tc358743 hacks 2022-06-06 20:26:09 +03:00
Maxim Devaev
054748234e refactoring 2022-06-06 19:15:55 +03:00
Maxim Devaev
53873e9ddb refactoring 2022-06-06 17:39:03 +03:00
Maxim Devaev
c21d0aef7e moved xioctl() to libs 2022-06-06 17:06:00 +03:00
Maxim Devaev
e505a56910 refactoring 2022-06-06 16:59:03 +03:00
Maxim Devaev
f4278f32c4 refactoring 2022-06-06 16:36:55 +03:00
Maxim Devaev
e9a6db02f6 refactoring 2022-06-06 16:17:34 +03:00
Maxim Devaev
63fe32ddd9 refactoring 2022-06-06 15:15:37 +03:00
Maxim Devaev
710652073a refactoring 2022-06-06 14:35:31 +03:00
Maxim Devaev
dded49cd83 resampler 2022-06-06 14:19:11 +03:00
Maxim Devaev
0f753dc654 queue fix 2022-06-06 02:04:16 +03:00
Maxim Devaev
c505a423af refactoring 2022-06-03 07:25:41 +03:00
Maxim Devaev
1cff2545b1 Bump version: 5.5 → 5.6 2022-06-02 02:18:13 +03:00
Maxim Devaev
3d994d6e67 fixed deps 2022-06-02 02:15:50 +03:00
57 changed files with 356 additions and 228 deletions

View File

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

View File

@@ -9,10 +9,10 @@ LDFLAGS ?=
# =====
_PLUGIN = libjanus_ustreamer.so
_CFLAGS = -fPIC -MD -c -std=c11 -Wall -Wextra -D_GNU_SOURCE $(shell pkg-config --cflags glib-2.0) $(CFLAGS)
_LDFLAGS = -shared -lm -pthread -lrt -ljansson -lopus -lasound $(shell pkg-config --libs glib-2.0) $(LDFLAGS)
_CFLAGS = -fPIC -MD -c -std=c17 -Wall -Wextra -D_GNU_SOURCE $(shell pkg-config --cflags glib-2.0) $(CFLAGS)
_LDFLAGS = -shared -lm -pthread -lrt -ljansson -lopus -lasound -lspeexdsp $(shell pkg-config --libs glib-2.0) $(LDFLAGS)
_SRCS = $(shell ls src/*.c)
_SRCS = $(shell ls src/uslibs/*.c src/*.c)
_BUILD = build

View File

@@ -2,9 +2,6 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
@@ -27,40 +24,48 @@
#define JLOG_PERROR_ALSA(_err, _prefix, _msg, ...) JLOG_ERROR(_prefix, _msg ": %s", ##__VA_ARGS__, snd_strerror(_err))
#define JLOG_PERROR_RES(_err, _prefix, _msg, ...) JLOG_ERROR(_prefix, _msg ": %s", ##__VA_ARGS__, speex_resampler_strerror(_err))
#define JLOG_PERROR_OPUS(_err, _prefix, _msg, ...) JLOG_ERROR(_prefix, _msg ": %s", ##__VA_ARGS__, opus_strerror(_err))
// A number of frames per 1 channel:
// - https://github.com/xiph/opus/blob/7b05f44/src/opus_demo.c#L368
#define HZ_TO_FRAMES(_hz) (6 * (_hz) / 50) // 120ms
#define HZ_TO_BUF16(_hz) (HZ_TO_FRAMES(_hz) * 2) // One stereo frame = (16bit L) + (16bit R)
#define HZ_TO_BUF8(_hz) (HZ_TO_BUF16(_hz) * sizeof(int16_t))
// https://github.com/xiph/opus/blob/7b05f44/src/opus_demo.c#L368
#define PCM_BITRATE 48000
#define PCM_FRAMES (6 * PCM_BITRATE / 50) // 120ms
#define PCM_DATA_SIZE (PCM_FRAMES * 2)
#define RAW_DATA_SIZE (PCM_DATA_SIZE * sizeof(opus_int16))
#define MIN_PCM_HZ 8000
#define MAX_PCM_HZ 192000
#define MAX_BUF16 HZ_TO_BUF16(MAX_PCM_HZ)
#define MAX_BUF8 HZ_TO_BUF8(MAX_PCM_HZ)
#define ENCODER_INPUT_HZ 48000
typedef struct {
opus_int16 data[PCM_DATA_SIZE];
} _pcm_buf_s;
int16_t data[MAX_BUF16];
} _pcm_buffer_s;
typedef struct {
uint8_t data[RAW_DATA_SIZE]; // Worst
uint8_t data[MAX_BUF8]; // Worst case
size_t used;
uint64_t pts;
} _enc_buf_s;
} _enc_buffer_s;
static void *_pcm_thread(void *v_audio);
static void *_encoder_thread(void *v_audio);
audio_s *audio_init(const char *name) {
audio_s *audio_init(const char *name, unsigned pcm_hz) {
audio_s *audio;
A_CALLOC(audio, 1);
audio->pcm_hz = pcm_hz;
audio->pcm_queue = queue_init(8);
audio->enc_queue = queue_init(8);
atomic_init(&audio->run, true);
atomic_init(&audio->stop, false);
int err;
{
int err;
if ((err = snd_pcm_open(&audio->pcm, name, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
audio->pcm = NULL;
JLOG_PERROR_ALSA(err, "audio", "Can't open PCM capture");
@@ -79,46 +84,39 @@ audio_s *audio_init(const char *name) {
SET_PARAM("Can't set PCM access type", snd_pcm_hw_params_set_access, SND_PCM_ACCESS_RW_INTERLEAVED);
SET_PARAM("Can't set PCM channels numbre", snd_pcm_hw_params_set_channels, 2);
SET_PARAM("Can't set PCM sampling format", snd_pcm_hw_params_set_format, SND_PCM_FORMAT_S16_LE);
unsigned pcm_bitrate = PCM_BITRATE;
SET_PARAM("Can't set PCM sampling rate", snd_pcm_hw_params_set_rate_near, &pcm_bitrate, 0);
if (pcm_bitrate != PCM_BITRATE) {
JLOG_ERROR("audio", "PCM bitrate mismatch: %u, should be %u", pcm_bitrate, PCM_BITRATE);
SET_PARAM("Can't set PCM sampling rate", snd_pcm_hw_params_set_rate_near, &audio->pcm_hz, 0);
if (audio->pcm_hz < MIN_PCM_HZ || audio->pcm_hz > MAX_PCM_HZ) {
JLOG_ERROR("audio", "Unsupported PCM freq: %u; should be: %u <= F <= %u",
audio->pcm_hz, MIN_PCM_HZ, MAX_PCM_HZ);
goto error;
}
SET_PARAM("Can't apply PCM params", snd_pcm_hw_params);
audio->pcm_frames = HZ_TO_FRAMES(audio->pcm_hz);
audio->pcm_size = HZ_TO_BUF8(audio->pcm_hz);
SET_PARAM("Can't apply PCM params", snd_pcm_hw_params);
# undef SET_PARAM
}
if (audio->pcm_hz != ENCODER_INPUT_HZ) {
audio->res = speex_resampler_init(2, audio->pcm_hz, ENCODER_INPUT_HZ, SPEEX_RESAMPLER_QUALITY_DESKTOP, &err);
if (err < 0) {
audio->res = NULL;
JLOG_PERROR_RES(err, "audio", "Can't create resampler");
goto error;
}
}
{
int err;
// OPUS_APPLICATION_VOIP
// OPUS_APPLICATION_RESTRICTED_LOWDELAY
audio->enc = opus_encoder_create(PCM_BITRATE, 2, OPUS_APPLICATION_AUDIO, &err);
if (err < 0) {
audio->enc = NULL;
JLOG_PERROR_OPUS(err, "audio", "Can't create OPUS encoder");
goto error;
}
# define SET_PARAM(_msg, _ctl) { \
if ((err = opus_encoder_ctl(audio->enc, _ctl)) < 0) { \
JLOG_PERROR_OPUS(err, "audio", _msg); \
goto error; \
} \
}
SET_PARAM("Can't set OPUS bitrate", OPUS_SET_BITRATE(48000));
SET_PARAM("Can't set OPUS max bandwidth", OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
SET_PARAM("Can't set OPUS signal type", OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
// Also see rtpa.c
// SET_PARAM("Can't set OPUS FEC", OPUS_SET_INBAND_FEC(1));
// SET_PARAM("Can't set OPUS exploss", OPUS_SET_PACKET_LOSS_PERC(10));
# undef SET_PARAM
// OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY
audio->enc = opus_encoder_create(ENCODER_INPUT_HZ, 2, OPUS_APPLICATION_AUDIO, &err);
assert(err == 0);
assert(!opus_encoder_ctl(audio->enc, OPUS_SET_BITRATE(48000)));
assert(!opus_encoder_ctl(audio->enc, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)));
assert(!opus_encoder_ctl(audio->enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)));
// OPUS_SET_INBAND_FEC(1), OPUS_SET_PACKET_LOSS_PERC(10): see rtpa.c
}
JLOG_INFO("audio", "PCM & OPUS prepared; capturing ...");
JLOG_INFO("audio", "Pipeline configured on %uHz; capturing ...", audio->pcm_hz);
audio->tids_created = true;
A_THREAD_CREATE(&audio->enc_tid, _encoder_thread, audio);
A_THREAD_CREATE(&audio->pcm_tid, _pcm_thread, audio);
@@ -132,13 +130,16 @@ audio_s *audio_init(const char *name) {
void audio_destroy(audio_s *audio) {
if (audio->tids_created) {
atomic_store(&audio->run, false);
atomic_store(&audio->stop, true);
A_THREAD_JOIN(audio->pcm_tid);
A_THREAD_JOIN(audio->enc_tid);
}
if (audio->enc) {
opus_encoder_destroy(audio->enc);
}
if (audio->res) {
speex_resampler_destroy(audio->res);
}
if (audio->pcm) {
snd_pcm_close(audio->pcm);
}
@@ -147,7 +148,7 @@ void audio_destroy(audio_s *audio) {
}
# define FREE_QUEUE(_suffix) { \
while (!queue_get_free(audio->_suffix##_queue)) { \
_##_suffix##_buf_s *ptr; \
_##_suffix##_buffer_s *ptr; \
assert(!queue_get(audio->_suffix##_queue, (void **)&ptr, 1)); \
free(ptr); \
} \
@@ -162,20 +163,20 @@ void audio_destroy(audio_s *audio) {
free(audio);
}
int audio_copy_encoded(audio_s *audio, uint8_t *data, size_t *size, uint64_t *pts) {
if (!atomic_load(&audio->run)) {
int audio_get_encoded(audio_s *audio, uint8_t *data, size_t *size, uint64_t *pts) {
if (atomic_load(&audio->stop)) {
return -1;
}
_enc_buf_s *in;
if (!queue_get(audio->enc_queue, (void **)&in, 1)) {
if (*size < in->used) {
free(in);
_enc_buffer_s *buf;
if (!queue_get(audio->enc_queue, (void **)&buf, 1)) {
if (*size < buf->used) {
free(buf);
return -3;
}
memcpy(data, in->data, in->used);
*size = in->used;
*pts = in->pts;
free(in);
memcpy(data, buf->data, buf->used);
*size = buf->used;
*pts = buf->pts;
free(buf);
return 0;
}
return -2;
@@ -185,32 +186,29 @@ static void *_pcm_thread(void *v_audio) {
A_THREAD_RENAME("us_a_pcm");
audio_s *audio = (audio_s *)v_audio;
uint8_t in[MAX_BUF8];
while (atomic_load(&audio->run)) {
uint8_t in[RAW_DATA_SIZE];
int frames = snd_pcm_readi(audio->pcm, in, PCM_FRAMES);
while (!atomic_load(&audio->stop)) {
int frames = snd_pcm_readi(audio->pcm, in, audio->pcm_frames);
if (frames < 0) {
JLOG_PERROR_ALSA(frames, "audio", "Can't capture PCM frames; breaking audio ...");
break;
} else if (frames < PCM_FRAMES) {
} else if (frames < (int)audio->pcm_frames) {
JLOG_ERROR("audio", "Too few PCM frames captured; breaking audio ...");
break;
}
if (queue_get_free(audio->pcm_queue)) {
_pcm_buf_s *out;
_pcm_buffer_s *out;
A_CALLOC(out, 1);
/*for (unsigned index = 0; index < RAW_DATA_SIZE; ++index) {
out->data[index] = (opus_int16)in[index * 2 + 1] << 8 | in[index * 2];
}*/
memcpy(out->data, in, RAW_DATA_SIZE);
memcpy(out->data, in, audio->pcm_size);
assert(!queue_put(audio->pcm_queue, out, 1));
} else {
JLOG_ERROR("audio", "PCM queue is full");
}
}
atomic_store(&audio->run, false);
atomic_store(&audio->stop, true);
return NULL;
}
@@ -218,13 +216,26 @@ static void *_encoder_thread(void *v_audio) {
A_THREAD_RENAME("us_a_enc");
audio_s *audio = (audio_s *)v_audio;
int16_t in_res[MAX_BUF16];
while (atomic_load(&audio->run)) {
_pcm_buf_s *in;
while (!atomic_load(&audio->stop)) {
_pcm_buffer_s *in;
if (!queue_get(audio->pcm_queue, (void **)&in, 1)) {
_enc_buf_s *out;
int16_t *in_ptr;
if (audio->res) {
assert(audio->pcm_hz != ENCODER_INPUT_HZ);
uint32_t in_count = audio->pcm_frames;
uint32_t out_count = HZ_TO_FRAMES(ENCODER_INPUT_HZ);
speex_resampler_process_interleaved_int(audio->res, in->data, &in_count, in_res, &out_count);
in_ptr = in_res;
} else {
assert(audio->pcm_hz == ENCODER_INPUT_HZ);
in_ptr = in->data;
}
_enc_buffer_s *out;
A_CALLOC(out, 1);
int size = opus_encode(audio->enc, in->data, PCM_FRAMES, out->data, RAW_DATA_SIZE);
int size = opus_encode(audio->enc, in_ptr, HZ_TO_FRAMES(ENCODER_INPUT_HZ), out->data, ARRAY_LEN(out->data));
free(in);
if (size < 0) {
JLOG_PERROR_OPUS(size, "audio", "Can't encode PCM frame to OPUS; breaking audio ...");
@@ -233,7 +244,8 @@ static void *_encoder_thread(void *v_audio) {
}
out->used = size;
out->pts = audio->pts;
audio->pts += PCM_FRAMES;
// https://datatracker.ietf.org/doc/html/rfc7587#section-4.2
audio->pts += HZ_TO_FRAMES(ENCODER_INPUT_HZ);
if (queue_get_free(audio->enc_queue)) {
assert(!queue_put(audio->enc_queue, out, 1));
@@ -244,6 +256,6 @@ static void *_encoder_thread(void *v_audio) {
}
}
atomic_store(&audio->run, false);
atomic_store(&audio->stop, true);
return NULL;
}

View File

@@ -2,9 +2,6 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
@@ -35,17 +32,23 @@
#include <pthread.h>
#include <alsa/asoundlib.h>
#include <speex/speex_resampler.h>
#include <opus/opus.h>
#include "tools.h"
#include "uslibs/tools.h"
#include "uslibs/threading.h"
#include "jlogging.h"
#include "threading.h"
#include "queue.h"
typedef struct {
snd_pcm_t *pcm;
unsigned pcm_hz;
unsigned pcm_frames;
size_t pcm_size;
snd_pcm_hw_params_t *pcm_params;
SpeexResamplerState *res;
OpusEncoder *enc;
queue_s *pcm_queue;
@@ -55,11 +58,11 @@ typedef struct {
pthread_t pcm_tid;
pthread_t enc_tid;
bool tids_created;
atomic_bool run;
atomic_bool stop;
} audio_s;
audio_s *audio_init(const char *name);
audio_s *audio_init(const char *name, unsigned pcm_hz);
void audio_destroy(audio_s *audio);
int audio_copy_encoded(audio_s *audio, uint8_t *data, size_t *size, uint64_t *pts);
int audio_get_encoded(audio_s *audio, uint8_t *data, size_t *size, uint64_t *pts);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,7 +22,7 @@
#include <janus/plugins/plugin.h>
#include "tools.h"
#include "uslibs/tools.h"
#define JLOG_INFO(_prefix, _msg, ...) JANUS_LOG(LOG_INFO, "== ustreamer/%-9s -- " _msg "\n", _prefix, ##__VA_ARGS__)

View File

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

View File

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

View File

@@ -38,13 +38,15 @@
#include <janus/config.h>
#include <janus/plugins/plugin.h>
#include "config.h"
#include "tools.h"
#include "uslibs/config.h"
#include "uslibs/tools.h"
#include "uslibs/threading.h"
#include "uslibs/list.h"
#include "uslibs/memsinksh.h"
#include "jlogging.h"
#include "threading.h"
#include "list.h"
#include "memsinksh.h"
#include "audio.h"
#include "tc358743.h"
#include "rtpv.h"
#include "rtpa.h"
@@ -121,6 +123,7 @@ const useconds_t _g_lock_polling = 1000;
const useconds_t _g_watchers_polling = 100000;
static char *_g_audio_dev = NULL;
static char *_g_tc358743_dev = NULL;
static _client_s *_g_clients = NULL;
static janus_callbacks *_g_gw = NULL;
@@ -128,14 +131,14 @@ static rtpv_s *_g_rtpv = NULL;
static rtpa_s *_g_rtpa = NULL;
static pthread_t _g_video_tid;
static atomic_bool _g_video_tid_created = ATOMIC_VAR_INIT(false);
static atomic_bool _g_video_tid_created = false;
static pthread_t _g_audio_tid;
static atomic_bool _g_audio_tid_created = ATOMIC_VAR_INIT(false);
static atomic_bool _g_audio_tid_created = false;
static pthread_mutex_t _g_lock = PTHREAD_MUTEX_INITIALIZER;
static atomic_bool _g_ready = ATOMIC_VAR_INIT(false);
static atomic_bool _g_stop = ATOMIC_VAR_INIT(false);
static atomic_bool _g_has_watchers = ATOMIC_VAR_INIT(false);
static atomic_bool _g_ready = false;
static atomic_bool _g_stop = false;
static atomic_bool _g_has_watchers = false;
#define LOCK A_MUTEX_LOCK(&_g_lock)
@@ -149,12 +152,12 @@ static int _wait_frame(int fd, memsink_shared_s* mem, uint64_t last_id) {
long double deadline_ts = get_now_monotonic() + _g_wait_timeout;
long double now;
do {
int retval = flock_timedwait_monotonic(fd, _g_lock_timeout);
int result = flock_timedwait_monotonic(fd, _g_lock_timeout);
now = get_now_monotonic();
if (retval < 0 && errno != EWOULDBLOCK) {
if (result < 0 && errno != EWOULDBLOCK) {
JLOG_PERROR("video", "Can't lock memsink");
return -1;
} else if (retval == 0) {
} else if (result == 0) {
if (mem->magic == MEMSINK_MAGIC && mem->version == MEMSINK_VERSION && mem->id != last_id) {
return 0;
}
@@ -272,6 +275,7 @@ static void *_clients_audio_thread(UNUSED void *arg) {
A_THREAD_RENAME("us_a_clients");
atomic_store(&_g_audio_tid_created, true);
assert(_g_audio_dev);
assert(_g_tc358743_dev);
while (!STOP) {
if (!HAS_WATCHERS) {
@@ -279,16 +283,30 @@ static void *_clients_audio_thread(UNUSED void *arg) {
continue;
}
tc358743_info_s info = {0};
audio_s *audio = NULL;
if ((audio = audio_init(_g_audio_dev)) == NULL) {
if (
tc358743_read_info(_g_tc358743_dev, &info) < 0
|| !info.has_audio
|| (audio = audio_init(_g_audio_dev, info.audio_hz)) == NULL
) {
goto close_audio;
}
while (!STOP && HAS_WATCHERS) {
if (
tc358743_read_info(_g_tc358743_dev, &info) < 0
|| !info.has_audio
|| audio->pcm_hz != info.audio_hz
) {
goto close_audio;
}
size_t size = RTP_DATAGRAM_SIZE - RTP_HEADER_SIZE;
uint8_t data[size];
uint64_t pts;
int result = audio_copy_encoded(audio, data, &size, &pts);
int result = audio_get_encoded(audio, data, &size, &pts);
if (result == 0) {
LOCK;
rtpa_wrap(_g_rtpa, data, size, pts);
@@ -336,6 +354,10 @@ static int _read_config(const char *config_dir_path) {
}
if ((_g_audio_dev = _get_config_value(config, "audio", "device")) != NULL) {
JLOG_INFO("main", "Enabled the experimental AUDIO feature");
if ((_g_tc358743_dev = _get_config_value(config, "audio", "tc358743")) == NULL) {
JLOG_INFO("main", "Missing config value: audio.tc358743");
goto error;
}
}
int retval = 0;
@@ -391,25 +413,14 @@ static void _plugin_destroy(void) {
});
_g_clients = NULL;
if (_g_rtpa) {
rtpa_destroy(_g_rtpa);
_g_rtpa = NULL;
}
rtpv_destroy(_g_rtpv);
_g_rtpv = NULL;
# define DEL(_func, _var) { if (_var) { _func(_var); _var = NULL; } }
DEL(rtpa_destroy, _g_rtpa);
DEL(rtpv_destroy, _g_rtpv);
_g_gw = NULL;
if (_g_audio_dev) {
free(_g_audio_dev);
_g_audio_dev = NULL;
}
if (_g_memsink_obj) {
free(_g_memsink_obj);
_g_memsink_obj = NULL;
}
DEL(free, _g_tc358743_dev);
DEL(free, _g_audio_dev);
DEL(free, _g_memsink_obj);
# undef DEL
}
#define IF_DISABLED(...) { if (!READY || STOP) { __VA_ARGS__ } }

View File

@@ -44,13 +44,14 @@ void queue_destroy(queue_s *queue) {
free(queue);
}
#define WAIT_LOOP(_var, _cond) { \
#define WAIT_OR_UNLOCK(_var, _cond) { \
struct timespec ts; \
assert(!clock_gettime(CLOCK_MONOTONIC, &ts)); \
ts.tv_sec += timeout; \
while (_var) { \
int err = pthread_cond_timedwait(_cond, &queue->mutex, &ts); \
if (err == ETIMEDOUT) { \
A_MUTEX_UNLOCK(&queue->mutex); \
return -1; \
} \
assert(!err); \
@@ -59,7 +60,7 @@ void queue_destroy(queue_s *queue) {
int queue_put(queue_s *queue, void *item, unsigned timeout) {
A_MUTEX_LOCK(&queue->mutex);
WAIT_LOOP(queue->size == queue->capacity, &queue->full_cond);
WAIT_OR_UNLOCK(queue->size == queue->capacity, &queue->full_cond);
queue->items[queue->in] = item;
++queue->size;
++queue->in;
@@ -71,7 +72,7 @@ int queue_put(queue_s *queue, void *item, unsigned timeout) {
int queue_get(queue_s *queue, void **item, unsigned timeout) {
A_MUTEX_LOCK(&queue->mutex);
WAIT_LOOP(queue->size == 0, &queue->empty_cond);
WAIT_OR_UNLOCK(queue->size == 0, &queue->empty_cond);
*item = queue->items[queue->out];
--queue->size;
++queue->out;
@@ -81,7 +82,7 @@ int queue_get(queue_s *queue, void **item, unsigned timeout) {
return 0;
}
#undef WAIT_LOOP
#undef WAIT_OR_UNLOCK
int queue_get_free(queue_s *queue) {
A_MUTEX_LOCK(&queue->mutex);

View File

@@ -27,8 +27,8 @@
#include <pthread.h>
#include "tools.h"
#include "threading.h"
#include "uslibs/tools.h"
#include "uslibs/threading.h"
// Based on https://github.com/seifzadeh/c-pthread-queue/blob/master/queue.h

View File

@@ -2,9 +2,6 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
@@ -31,7 +28,7 @@
#include <sys/types.h>
#include "tools.h"
#include "uslibs/tools.h"
// https://stackoverflow.com/questions/47635545/why-webrtc-chose-rtp-max-packet-size-to-1200-bytes

View File

@@ -2,9 +2,6 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #

View File

@@ -2,9 +2,6 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
@@ -32,9 +29,9 @@
#include <sys/types.h>
#include "tools.h"
#include "threading.h"
#include "audio.h"
#include "uslibs/tools.h"
#include "uslibs/threading.h"
#include "rtp.h"

View File

@@ -2,9 +2,6 @@
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# This source file is partially based on this code: #
# - https://github.com/catid/kvm/blob/master/kvm_pipeline/src #
# #
# Copyright (C) 2018-2022 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
@@ -36,10 +33,11 @@
#include <pthread.h>
#include "tools.h"
#include "threading.h"
#include "frame.h"
#include "base64.h"
#include "uslibs/tools.h"
#include "uslibs/threading.h"
#include "uslibs/frame.h"
#include "uslibs/base64.h"
#include "rtp.h"

64
janus/src/tc358743.c Normal file
View File

@@ -0,0 +1,64 @@
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2022 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 "tc358743.h"
#ifndef V4L2_CID_USER_TC358743_BASE
# define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080)
#endif
#ifndef TC358743_CID_AUDIO_PRESENT
# define TC358743_CID_AUDIO_PRESENT (V4L2_CID_USER_TC358743_BASE + 1)
#endif
#ifndef TC358743_CID_AUDIO_SAMPLING_RATE
# define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0)
#endif
int tc358743_read_info(const char *path, tc358743_info_s *info) {
MEMSET_ZERO(*info);
int fd = -1;
if ((fd = open(path, O_RDWR)) < 0) {
JLOG_PERROR("audio", "Can't open TC358743 V4L2 device");
return -1;
}
# define READ_CID(_cid, _field) { \
struct v4l2_control ctl = {0}; \
ctl.id = _cid; \
if (xioctl(fd, VIDIOC_G_CTRL, &ctl) < 0) { \
JLOG_PERROR("audio", "Can't get value of " #_cid); \
close(fd); \
return -1; \
} \
info->_field = ctl.value; \
}
READ_CID(TC358743_CID_AUDIO_PRESENT, has_audio);
READ_CID(TC358743_CID_AUDIO_SAMPLING_RATE, audio_hz);
# undef READ_CID
close(fd);
return 0;
}

46
janus/src/tc358743.h Normal file
View File

@@ -0,0 +1,46 @@
/*****************************************************************************
# #
# uStreamer - Lightweight and fast MJPEG-HTTP streamer. #
# #
# Copyright (C) 2018-2022 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 <unistd.h>
#include <fcntl.h>
#include <stdbool.h>
#include <sys/types.h>
#include <linux/videodev2.h>
#include <linux/v4l2-controls.h>
#include "uslibs/tools.h"
#include "uslibs/xioctl.h"
#include "jlogging.h"
typedef struct {
bool has_audio;
unsigned audio_hz;
} tc358743_info_s;
int tc358743_read_info(const char *path, tc358743_info_s *info);

View File

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

View File

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

1
janus/src/uslibs/base64.c Symbolic link
View File

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

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

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

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

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

1
janus/src/uslibs/frame.c Symbolic link
View File

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

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

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

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

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

View File

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

View File

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

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

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

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

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

View File

@@ -1,3 +1,6 @@
#define CHAR_BIT 8
#define WITH_GPIO
#define JANUS_PLUGIN_INIT(...) { __VA_ARGS__ }
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED 1
#define CLOCK_MONOTONIC_RAW 1
#define CLOCK_MONOTONIC_FAST 1

View File

@@ -15,15 +15,8 @@ disable =
locally-disabled,
fixme,
missing-docstring,
no-init,
no-self-use,
superfluous-parens,
abstract-class-not-used,
abstract-class-little-used,
duplicate-code,
bad-continuation,
bad-whitespace,
star-args,
broad-except,
redundant-keyword-arg,
wrong-import-order,
@@ -39,9 +32,6 @@ msg-template = {symbol} -- {path}:{line}({obj}): {msg}
max-line-length = 160
[BASIC]
# List of builtins function names that should not be used, separated by a comma
bad-functions =
# Good variable names which should always be accepted, separated by a comma
good-names = _, __, x, y, ws, make-html-h, make-jpeg-h

View File

@@ -9,8 +9,9 @@ changedir = /src
[testenv:cppcheck]
whitelist_externals = cppcheck
commands = cppcheck \
-j4 \
--force \
--std=c11 \
--std=c17 \
--error-exitcode=1 \
--quiet \
--enable=warning,unusedFunction,portability,performance,style \
@@ -19,7 +20,7 @@ commands = cppcheck \
--inline-suppr \
--library=python \
--include=linters/cppcheck.h \
src python/ustreamer.c janus/rtp.h janus/rtp.c janus/plugin.c
src python/*.? janus/*.?
[testenv:flake8]
whitelist_externals = bash

View File

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

View File

@@ -1,6 +1,6 @@
.\" Manpage for ustreamer.
.\" Open an issue or pull request to https://github.com/pikvm/ustreamer to correct errors or typos
.TH USTREAMER 1 "version 5.5" "November 2020"
.TH USTREAMER 1 "version 5.7" "November 2020"
.SH NAME
ustreamer \- stream MJPEG video from any V4L2 device to the network

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer
pkgver=5.5
pkgver=5.7
pkgrel=1
pkgdesc="Lightweight and fast MJPEG-HTTP streamer"
url="https://github.com/pikvm/ustreamer"
@@ -22,8 +22,8 @@ if [ -e /usr/bin/python3 ]; then
makedepends+=(python-setuptools)
fi
if [ -e /usr/include/janus/plugins/plugin.h ];then
depends+=(janus-gateway-pikvm)
makedepends+=(janus-gateway-pikvm)
depends+=(janus-gateway-pikvm alsa-lib opus)
makedepends+=(janus-gateway-pikvm alsa-lib opus)
_options="$_options WITH_JANUS=1"
fi

View File

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

View File

@@ -1,14 +1,25 @@
import os
from typing import List
from setuptools import Extension
from setuptools import setup
# =====
def _find_sources(suffix: str) -> List[str]:
sources: List[str] = []
for (root_path, _, names) in os.walk("src"):
for name in names:
if name.endswith(suffix):
sources.append(os.path.join(root_path, name))
return sources
if __name__ == "__main__":
setup(
name="ustreamer",
version="5.5",
version="5.7",
description="uStreamer tools",
author="Maxim Devaev",
author_email="mdevaev@gmail.com",
@@ -17,9 +28,10 @@ if __name__ == "__main__":
Extension(
"ustreamer",
libraries=["rt", "m", "pthread"],
extra_compile_args=["-std=c17", "-D_GNU_SOURCE"],
undef_macros=["NDEBUG"],
sources=["src/" + name for name in os.listdir("src") if name.endswith(".c")],
depends=["src/" + name for name in os.listdir("src") if name.endswith(".h")],
sources=_find_sources(".c"),
depends=_find_sources(".h"),
),
],
)

View File

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

View File

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

View File

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

View File

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

1
python/src/uslibs/frame.c Symbolic link
View File

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

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

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

View File

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

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

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

View File

@@ -13,9 +13,9 @@
#include <Python.h>
#include "tools.h"
#include "frame.h"
#include "memsinksh.h"
#include "uslibs/tools.h"
#include "uslibs/frame.h"
#include "uslibs/memsinksh.h"
typedef struct {

View File

@@ -10,7 +10,7 @@ LDFLAGS ?=
_USTR = ustreamer.bin
_DUMP = ustreamer-dump.bin
_CFLAGS = -MD -c -std=c11 -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

View File

@@ -23,7 +23,7 @@
#pragma once
#define VERSION_MAJOR 5
#define VERSION_MINOR 5
#define VERSION_MINOR 7
#define MAKE_VERSION2(_major, _minor) #_major "." #_minor
#define MAKE_VERSION1(_major, _minor) MAKE_VERSION2(_major, _minor)

View File

@@ -35,6 +35,7 @@
#include <time.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/file.h>

View File

@@ -26,8 +26,7 @@
#include <sys/ioctl.h>
#include "../libs/tools.h"
#include "../libs/logging.h"
#include "tools.h"
#ifndef CFG_XIOCTL_RETRIES
@@ -51,10 +50,5 @@ INLINE int xioctl(int fd, int request, void *arg) {
|| errno == ETIMEDOUT
)
);
// cppcheck-suppress knownConditionTrueFalse
if (retval && retries <= 0) {
LOG_PERROR("ioctl(%d) retried %u times; giving up", request, XIOCTL_RETRIES);
}
return retval;
}

View File

@@ -80,7 +80,8 @@ static const char *_standard_to_string(v4l2_std_id standard);
static const char *_io_method_to_string_supported(enum v4l2_memory io_method);
#define RUN(_next) dev->run->_next
#define RUN(_next) dev->run->_next
#define D_XIOCTL(...) xioctl(RUN(fd), __VA_ARGS__)
device_s *device_init(void) {
@@ -222,7 +223,7 @@ int device_export_to_dma(device_s *dev) {
exp.index = index;
LOG_DEBUG("Exporting device buffer=%u to DMA ...", index);
if (xioctl(RUN(fd), VIDIOC_EXPBUF, &exp) < 0) {
if (D_XIOCTL(VIDIOC_EXPBUF, &exp) < 0) {
LOG_PERROR("Can't export device buffer=%u to DMA", index);
goto error;
}
@@ -248,7 +249,7 @@ int device_switch_capturing(device_s *dev, bool enable) {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
LOG_DEBUG("%s device capturing ...", (enable ? "Starting" : "Stopping"));
if (xioctl(RUN(fd), (enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type) < 0) {
if (D_XIOCTL((enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type) < 0) {
LOG_PERROR("Can't %s capturing", (enable ? "start" : "stop"));
if (enable) {
return -1;
@@ -315,7 +316,7 @@ int device_grab_buffer(device_s *dev, hw_buffer_s **hw) {
buf.memory = dev->io_method;
LOG_DEBUG("Grabbing device buffer ...");
if (xioctl(RUN(fd), VIDIOC_DQBUF, &buf) < 0) {
if (D_XIOCTL(VIDIOC_DQBUF, &buf) < 0) {
LOG_PERROR("Can't grab device buffer");
return -1;
}
@@ -336,7 +337,7 @@ int device_grab_buffer(device_s *dev, hw_buffer_s **hw) {
LOG_DEBUG("Dropped too small frame, assuming it was broken: buffer=%u, bytesused=%u",
buf.index, buf.bytesused);
LOG_DEBUG("Releasing device buffer=%u (broken frame) ...", buf.index);
if (xioctl(RUN(fd), VIDIOC_QBUF, &buf) < 0) {
if (D_XIOCTL(VIDIOC_QBUF, &buf) < 0) {
LOG_PERROR("Can't release device buffer=%u (broken frame)", buf.index);
return -1;
}
@@ -370,7 +371,7 @@ int device_release_buffer(device_s *dev, hw_buffer_s *hw) {
const unsigned index = hw->buf.index;
LOG_DEBUG("Releasing device buffer=%u ...", index);
if (xioctl(RUN(fd), VIDIOC_QBUF, &hw->buf) < 0) {
if (D_XIOCTL(VIDIOC_QBUF, &hw->buf) < 0) {
LOG_PERROR("Can't release device buffer=%u", index);
return -1;
}
@@ -382,7 +383,7 @@ int device_consume_event(device_s *dev) {
struct v4l2_event event;
LOG_DEBUG("Consuming V4L2 event ...");
if (xioctl(RUN(fd), VIDIOC_DQEVENT, &event) == 0) {
if (D_XIOCTL(VIDIOC_DQEVENT, &event) == 0) {
switch (event.type) {
case V4L2_EVENT_SOURCE_CHANGE:
LOG_INFO("Got V4L2_EVENT_SOURCE_CHANGE: source changed");
@@ -401,7 +402,7 @@ static int _device_open_check_cap(device_s *dev) {
struct v4l2_capability cap = {0};
LOG_DEBUG("Querying device capabilities ...");
if (xioctl(RUN(fd), VIDIOC_QUERYCAP, &cap) < 0) {
if (D_XIOCTL(VIDIOC_QUERYCAP, &cap) < 0) {
LOG_PERROR("Can't query device capabilities");
return -1;
}
@@ -418,14 +419,14 @@ static int _device_open_check_cap(device_s *dev) {
int input = dev->input; // Needs a pointer to int for ioctl()
LOG_INFO("Using input channel: %d", input);
if (xioctl(RUN(fd), VIDIOC_S_INPUT, &input) < 0) {
if (D_XIOCTL(VIDIOC_S_INPUT, &input) < 0) {
LOG_ERROR("Can't set input channel");
return -1;
}
if (dev->standard != V4L2_STD_UNKNOWN) {
LOG_INFO("Using TV standard: %s", _standard_to_string(dev->standard));
if (xioctl(RUN(fd), VIDIOC_S_STD, &dev->standard) < 0) {
if (D_XIOCTL(VIDIOC_S_STD, &dev->standard) < 0) {
LOG_ERROR("Can't set video standard");
return -1;
}
@@ -448,7 +449,7 @@ static int _device_open_dv_timings(device_s *dev) {
sub.type = V4L2_EVENT_SOURCE_CHANGE;
LOG_DEBUG("Subscribing to DV-timings events ...")
if (xioctl(RUN(fd), VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) {
if (D_XIOCTL(VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) {
LOG_PERROR("Can't subscribe to DV-timings events");
return -1;
}
@@ -459,8 +460,8 @@ static int _device_open_dv_timings(device_s *dev) {
static int _device_apply_dv_timings(device_s *dev) {
struct v4l2_dv_timings dv = {0};
LOG_DEBUG("Calling ioctl(VIDIOC_QUERY_DV_TIMINGS) ...");
if (xioctl(RUN(fd), VIDIOC_QUERY_DV_TIMINGS, &dv) == 0) {
LOG_DEBUG("Calling xioctl(VIDIOC_QUERY_DV_TIMINGS) ...");
if (D_XIOCTL(VIDIOC_QUERY_DV_TIMINGS, &dv) == 0) {
if (dv.type == V4L2_DV_BT_656_1120) {
// See v4l2_print_dv_timings() in the kernel
unsigned htot = V4L2_DV_BT_FRAME_WIDTH(&dv.bt);
@@ -478,8 +479,8 @@ static int _device_apply_dv_timings(device_s *dev) {
(unsigned long long)dv.bt.pixelclock, dv.bt.vsync, dv.bt.hsync);
}
LOG_DEBUG("Calling ioctl(VIDIOC_S_DV_TIMINGS) ...");
if (xioctl(RUN(fd), VIDIOC_S_DV_TIMINGS, &dv) < 0) {
LOG_DEBUG("Calling xioctl(VIDIOC_S_DV_TIMINGS) ...");
if (D_XIOCTL(VIDIOC_S_DV_TIMINGS, &dv) < 0) {
LOG_PERROR("Failed to set DV-timings");
return -1;
}
@@ -489,10 +490,10 @@ static int _device_apply_dv_timings(device_s *dev) {
}
} else {
LOG_DEBUG("Calling ioctl(VIDIOC_QUERYSTD) ...");
if (xioctl(RUN(fd), VIDIOC_QUERYSTD, &dev->standard) == 0) {
LOG_DEBUG("Calling xioctl(VIDIOC_QUERYSTD) ...");
if (D_XIOCTL(VIDIOC_QUERYSTD, &dev->standard) == 0) {
LOG_INFO("Applying the new VIDIOC_S_STD: %s ...", _standard_to_string(dev->standard));
if (xioctl(RUN(fd), VIDIOC_S_STD, &dev->standard) < 0) {
if (D_XIOCTL(VIDIOC_S_STD, &dev->standard) < 0) {
LOG_PERROR("Can't set video standard");
return -1;
}
@@ -515,7 +516,7 @@ static int _device_open_format(device_s *dev, bool first) {
// Set format
LOG_DEBUG("Probing device format=%s, stride=%u, resolution=%ux%u ...",
_format_to_string_supported(dev->format), stride, RUN(width), RUN(height));
if (xioctl(RUN(fd), VIDIOC_S_FMT, &fmt) < 0) {
if (D_XIOCTL(VIDIOC_S_FMT, &fmt) < 0) {
LOG_PERROR("Can't set device format");
return -1;
}
@@ -566,7 +567,7 @@ static void _device_open_hw_fps(device_s *dev) {
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
LOG_DEBUG("Querying HW FPS ...");
if (xioctl(RUN(fd), VIDIOC_G_PARM, &setfps) < 0) {
if (D_XIOCTL(VIDIOC_G_PARM, &setfps) < 0) {
if (errno == ENOTTY) { // Quiet message for TC358743
LOG_INFO("Querying HW FPS changing is not supported");
} else {
@@ -587,7 +588,7 @@ static void _device_open_hw_fps(device_s *dev) {
SETFPS_TPF(numerator) = 1;
SETFPS_TPF(denominator) = (dev->desired_fps == 0 ? 255 : dev->desired_fps);
if (xioctl(RUN(fd), VIDIOC_S_PARM, &setfps) < 0) {
if (D_XIOCTL(VIDIOC_S_PARM, &setfps) < 0) {
LOG_PERROR("Can't set HW FPS");
return;
}
@@ -618,11 +619,11 @@ static void _device_open_jpeg_quality(device_s *dev) {
if (is_jpeg(RUN(format))) {
struct v4l2_jpegcompression comp = {0};
if (xioctl(RUN(fd), VIDIOC_G_JPEGCOMP, &comp) < 0) {
if (D_XIOCTL(VIDIOC_G_JPEGCOMP, &comp) < 0) {
LOG_ERROR("Device doesn't support setting of HW encoding quality parameters");
} else {
comp.quality = dev->jpeg_quality;
if (xioctl(RUN(fd), VIDIOC_S_JPEGCOMP, &comp) < 0) {
if (D_XIOCTL(VIDIOC_S_JPEGCOMP, &comp) < 0) {
LOG_ERROR("Can't change MJPEG quality for JPEG source with HW pass-through encoder");
} else {
quality = dev->jpeg_quality;
@@ -650,7 +651,7 @@ static int _device_open_io_method_mmap(device_s *dev) {
req.memory = V4L2_MEMORY_MMAP;
LOG_DEBUG("Requesting %u device buffers for MMAP ...", req.count);
if (xioctl(RUN(fd), VIDIOC_REQBUFS, &req) < 0) {
if (D_XIOCTL(VIDIOC_REQBUFS, &req) < 0) {
LOG_PERROR("Device '%s' doesn't support MMAP method", dev->path);
return -1;
}
@@ -671,8 +672,8 @@ static int _device_open_io_method_mmap(device_s *dev) {
buf.memory = V4L2_MEMORY_MMAP;
buf.index = RUN(n_bufs);
LOG_DEBUG("Calling ioctl(VIDIOC_QUERYBUF) for device buffer=%u ...", RUN(n_bufs));
if (xioctl(RUN(fd), VIDIOC_QUERYBUF, &buf) < 0) {
LOG_DEBUG("Calling xioctl(VIDIOC_QUERYBUF) for device buffer=%u ...", RUN(n_bufs));
if (D_XIOCTL(VIDIOC_QUERYBUF, &buf) < 0) {
LOG_PERROR("Can't VIDIOC_QUERYBUF");
return -1;
}
@@ -707,7 +708,7 @@ static int _device_open_io_method_userptr(device_s *dev) {
req.memory = V4L2_MEMORY_USERPTR;
LOG_DEBUG("Requesting %u device buffers for USERPTR ...", req.count);
if (xioctl(RUN(fd), VIDIOC_REQBUFS, &req) < 0) {
if (D_XIOCTL(VIDIOC_REQBUFS, &req) < 0) {
LOG_PERROR("Device '%s' doesn't support USERPTR method", dev->path);
return -1;
}
@@ -747,8 +748,8 @@ static int _device_open_queue_buffers(device_s *dev) {
buf.length = RUN(hw_bufs)[index].raw.allocated;
}
LOG_DEBUG("Calling ioctl(VIDIOC_QBUF) for buffer=%u ...", index);
if (xioctl(RUN(fd), VIDIOC_QBUF, &buf) < 0) {
LOG_DEBUG("Calling xioctl(VIDIOC_QBUF) for buffer=%u ...", index);
if (D_XIOCTL(VIDIOC_QBUF, &buf) < 0) {
LOG_PERROR("Can't VIDIOC_QBUF");
return -1;
}
@@ -836,7 +837,7 @@ static int _device_query_control(
MEMSET_ZERO(*query);
query->id = cid;
if (xioctl(RUN(fd), VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) {
if (D_XIOCTL(VIDIOC_QUERYCTRL, query) < 0 || query->flags & V4L2_CTRL_FLAG_DISABLED) {
if (!quiet) {
LOG_ERROR("Changing control %s is unsupported", name);
}
@@ -861,7 +862,7 @@ static void _device_set_control(
ctl.id = cid;
ctl.value = value;
if (xioctl(RUN(fd), VIDIOC_S_CTRL, &ctl) < 0) {
if (D_XIOCTL(VIDIOC_S_CTRL, &ctl) < 0) {
if (!quiet) {
LOG_PERROR("Can't set control %s", name);
}
@@ -902,4 +903,5 @@ static const char *_io_method_to_string_supported(enum v4l2_memory io_method) {
return "unsupported";
}
# undef RUN
#undef D_XIOCTL
#undef RUN

View File

@@ -45,8 +45,7 @@
#include "../libs/logging.h"
#include "../libs/threading.h"
#include "../libs/frame.h"
#include "xioctl.h"
#include "../libs/xioctl.h"
#define VIDEO_MIN_WIDTH ((unsigned)160)

View File

@@ -39,8 +39,7 @@
#include "../libs/tools.h"
#include "../libs/logging.h"
#include "../libs/frame.h"
#include "xioctl.h"
#include "../libs/xioctl.h"
typedef struct {