mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-10-19 20:24:22 +00:00
webcam: janus plugin
This commit is contained in:
@@ -56,7 +56,7 @@ us_memsink_s *us_memsink_init_opened(
|
||||
|
||||
US_LOG_INFO("Using %s-sink: %s", name, obj);
|
||||
|
||||
if ((sink->data_size = us_memsink_calculate_size(obj)) == 0) {
|
||||
if ((sink->data_size = us_memsinksh_calculate_size(obj)) == 0) {
|
||||
US_LOG_ERROR("%s-sink: Invalid object suffix", name);
|
||||
goto error;
|
||||
}
|
||||
@@ -75,7 +75,7 @@ us_memsink_s *us_memsink_init_opened(
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((sink->mem = us_memsink_shared_map(sink->fd, sink->data_size)) == NULL) {
|
||||
if ((sink->mem = us_memsinksh_map(sink->fd, sink->data_size)) == NULL) {
|
||||
US_LOG_PERROR("%s-sink: Can't mmap shared memory", name);
|
||||
goto error;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ error:
|
||||
|
||||
void us_memsink_destroy(us_memsink_s *sink) {
|
||||
if (sink->mem != NULL) {
|
||||
if (us_memsink_shared_unmap(sink->mem, sink->data_size) < 0) {
|
||||
if (us_memsinksh_unmap(sink->mem, sink->data_size) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't unmap shared memory", sink->name);
|
||||
}
|
||||
}
|
||||
@@ -143,11 +143,10 @@ bool us_memsink_server_check(us_memsink_s *sink, const us_frame_s *frame) {
|
||||
}
|
||||
|
||||
// Проверяем, есть ли у нас живой клиент по таймауту
|
||||
const bool has_clients = (sink->mem->last_client_ts + sink->client_ttl > us_get_now_monotonic());
|
||||
const bool has_clients = us_memsinksh_has_clients(sink->mem, sink->client_ttl);
|
||||
atomic_store(&sink->has_clients, has_clients);
|
||||
|
||||
if (flock(sink->fd, LOCK_UN) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name);
|
||||
if (us_memsink_server_x_unlock(sink) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (has_clients) {
|
||||
@@ -163,45 +162,34 @@ 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,
|
||||
us_memsink_wants_s *wants
|
||||
us_memsink_wants_s *w_get
|
||||
) {
|
||||
US_A(sink->server);
|
||||
|
||||
const ldf now = us_get_now_monotonic();
|
||||
|
||||
if (frame->used > sink->data_size) {
|
||||
US_LOG_ERROR("%s-sink: Can't put frame: is too big (%zu > %zu)",
|
||||
sink->name, frame->used, sink->data_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (us_flock_timedwait_monotonic(sink->fd, 1) == 0) {
|
||||
US_LOG_VERBOSE("%s-sink: >>>>> Exposing new frame ...", sink->name);
|
||||
|
||||
sink->mem->id = us_get_now_id();
|
||||
if (sink->mem->wants.key && frame->key) {
|
||||
sink->mem->wants.key = false;
|
||||
}
|
||||
if (wants != NULL) {
|
||||
memcpy(wants, &sink->mem->wants, sizeof(us_memsink_wants_s));
|
||||
}
|
||||
|
||||
memcpy(us_memsink_get_data(sink->mem), frame->data, frame->used);
|
||||
sink->mem->used = frame->used;
|
||||
US_FRAME_COPY_META(frame, sink->mem);
|
||||
|
||||
sink->mem->magic = US_MEMSINK_MAGIC;
|
||||
sink->mem->version = US_MEMSINK_VERSION;
|
||||
|
||||
const bool has_clients = (sink->mem->last_client_ts + sink->client_ttl > us_get_now_monotonic());
|
||||
const bool has_clients = us_memsinksh_has_clients(sink->mem, sink->client_ttl);
|
||||
atomic_store(&sink->has_clients, has_clients);
|
||||
|
||||
if (flock(sink->fd, LOCK_UN) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name);
|
||||
US_LOG_VERBOSE("%s-sink: >>>>> Exposing new frame ...", sink->name);
|
||||
const bool exposed = !us_memsink_server_x_put(sink, frame);
|
||||
|
||||
if (w_get != NULL) {
|
||||
if (has_clients) {
|
||||
memcpy(w_get, &sink->mem->wants, sizeof(us_memsink_wants_s));
|
||||
} else {
|
||||
US_MEMSET_ZERO(*w_get);
|
||||
}
|
||||
}
|
||||
|
||||
if (us_memsink_server_x_unlock(sink) < 0) {
|
||||
return -1;
|
||||
}
|
||||
US_LOG_VERBOSE("%s-sink: Exposed new frame; full exposition time = %.3Lf",
|
||||
sink->name, us_get_now_monotonic() - now);
|
||||
if (exposed) {
|
||||
US_LOG_VERBOSE("%s-sink: Exposed new frame; full exposition time = %.3Lf",
|
||||
sink->name, us_get_now_monotonic() - now);
|
||||
}
|
||||
|
||||
} else if (errno == EWOULDBLOCK) {
|
||||
US_LOG_VERBOSE("%s-sink: ===== Shared memory is busy now; frame skipped", sink->name);
|
||||
@@ -216,8 +204,8 @@ int us_memsink_server_put(
|
||||
int us_memsink_client_get(
|
||||
us_memsink_s *sink,
|
||||
us_frame_s *frame,
|
||||
us_memsink_wants_s *get,
|
||||
const us_memsink_wants_s *put
|
||||
us_memsink_wants_s *w_get,
|
||||
const us_memsink_wants_s *w_put
|
||||
) {
|
||||
US_A(!sink->server); // Client only
|
||||
|
||||
@@ -242,33 +230,121 @@ int us_memsink_client_get(
|
||||
goto done;
|
||||
}
|
||||
|
||||
const bool had_client_magic = (sink->mem->client_magic == US_MEMSINK_MAGIC);
|
||||
// Let the sink know that the client is alive
|
||||
sink->mem->last_client_ts = us_get_now_monotonic();
|
||||
sink->mem->client_magic = US_MEMSINK_MAGIC;
|
||||
|
||||
if (sink->mem->id == sink->last_readed_id) {
|
||||
retval = US_ERROR_NO_DATA; // Not updated
|
||||
if (sink->mem->used == 0 || sink->mem->id == sink->last_readed_id) {
|
||||
// ^ Zero frame |OR| ^ Not updated
|
||||
retval = US_ERROR_NO_DATA;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sink->last_readed_id = sink->mem->id;
|
||||
us_frame_set_data(frame, us_memsink_get_data(sink->mem), sink->mem->used);
|
||||
us_frame_set_data(frame, us_memsinksh_get_data(sink->mem), sink->mem->used);
|
||||
US_FRAME_COPY_META(sink->mem, frame);
|
||||
|
||||
if (get != NULL) {
|
||||
memcpy(get, &sink->mem->wants, sizeof(us_memsink_wants_s));
|
||||
}
|
||||
if (put != NULL) {
|
||||
const bool key = sink->mem->wants.key;
|
||||
memcpy(&sink->mem->wants, put, sizeof(us_memsink_wants_s));
|
||||
if (key) {
|
||||
sink->mem->wants.key = key;
|
||||
if (w_get != NULL) {
|
||||
if (had_client_magic) { // Чтобы не прочитать мусор, если не было клиентов
|
||||
memcpy(w_get, &sink->mem->wants, sizeof(us_memsink_wants_s));
|
||||
} else {
|
||||
US_MEMSET_ZERO(*w_get);
|
||||
}
|
||||
}
|
||||
|
||||
if (w_put != NULL) {
|
||||
const bool key = sink->mem->wants.key;
|
||||
memcpy(&sink->mem->wants, w_put, sizeof(us_memsink_wants_s));
|
||||
if (key) {
|
||||
sink->mem->wants.key = key;
|
||||
}
|
||||
} else {
|
||||
US_MEMSET_ZERO(sink->mem->wants);
|
||||
}
|
||||
|
||||
done:
|
||||
if (flock(sink->fd, LOCK_UN) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name);
|
||||
if (us_memsink_server_x_unlock(sink) < 0) {
|
||||
retval = -1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
us_mss_lock_result_e us_memsink_server_x_lock(
|
||||
us_memsink_s *sink,
|
||||
us_memsink_wants_s *w_get
|
||||
) {
|
||||
US_A(sink->server);
|
||||
|
||||
if (us_flock_timedwait_monotonic(sink->fd, 1) < 0) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
return US_MSS_BUSY;
|
||||
}
|
||||
US_LOG_PERROR("%s-sink: Can't lock memory", sink->name);
|
||||
return US_MSS_ERROR;
|
||||
}
|
||||
|
||||
if (sink->mem->magic == US_MEMSINK_MAGIC && sink->mem->version == US_MEMSINK_VERSION) {
|
||||
// Если инициализировано - значит клиенту что-то уже могли написать
|
||||
const bool has_clients = us_memsinksh_has_clients(sink->mem, sink->client_ttl);
|
||||
atomic_store(&sink->has_clients, has_clients);
|
||||
if (has_clients) {
|
||||
if (w_get != NULL) {
|
||||
memcpy(w_get, &sink->mem->wants, sizeof(us_memsink_wants_s));
|
||||
}
|
||||
// sink->unsafe_last_client_ts = sink->mem->last_client_ts; // _x_ functions don't use it
|
||||
return US_MSS_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
// А иначе скормим клиентам инициализацию с пустым фреймом,
|
||||
// в следующий раз прочтем от них что-то путное.
|
||||
us_memsink_server_x_put(sink, NULL);
|
||||
}
|
||||
|
||||
if (us_memsink_server_x_unlock(sink) < 0) {
|
||||
return US_MSS_ERROR;
|
||||
}
|
||||
return US_MSS_NO_CLIENT;
|
||||
}
|
||||
|
||||
bool us_memsink_server_x_is_consumed(us_memsink_s *sink) {
|
||||
return (sink->mem->used == 0);
|
||||
}
|
||||
|
||||
void us_memsink_server_x_set_consumed(us_memsink_s *sink) {
|
||||
sink->mem->used = 0;
|
||||
}
|
||||
|
||||
int us_memsink_server_x_put(us_memsink_s *sink, const us_frame_s *frame) {
|
||||
if (frame != NULL) {
|
||||
if (frame->used > sink->data_size) {
|
||||
US_LOG_ERROR("%s-sink: Can't put frame: it's too big (%zu > %zu)",
|
||||
sink->name, frame->used, sink->data_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(us_memsinksh_get_data(sink->mem), frame->data, frame->used);
|
||||
sink->mem->used = frame->used;
|
||||
US_FRAME_COPY_META(frame, sink->mem);
|
||||
|
||||
if (sink->mem->wants.key && frame->key) {
|
||||
// Можем писать в мусор, но пофигу
|
||||
sink->mem->wants.key = false;
|
||||
}
|
||||
} else {
|
||||
sink->mem->used = 0;
|
||||
}
|
||||
|
||||
sink->mem->id = us_get_now_id();
|
||||
sink->mem->version = US_MEMSINK_VERSION;
|
||||
sink->mem->magic = US_MEMSINK_MAGIC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int us_memsink_server_x_unlock(us_memsink_s *sink) {
|
||||
if (flock(sink->fd, LOCK_UN) < 0) {
|
||||
US_LOG_PERROR("%s-sink: Can't unlock memory", sink->name);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -61,10 +61,32 @@ 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,
|
||||
us_memsink_wants_s *wants);
|
||||
us_memsink_wants_s *w_get);
|
||||
|
||||
int us_memsink_client_get(
|
||||
us_memsink_s *sink,
|
||||
us_frame_s *frame,
|
||||
us_memsink_wants_s *get,
|
||||
const us_memsink_wants_s *put);
|
||||
us_memsink_wants_s *w_get,
|
||||
const us_memsink_wants_s *w_put);
|
||||
|
||||
|
||||
// Low-level
|
||||
|
||||
typedef enum {
|
||||
US_MSS_SUCCESS = 0,
|
||||
US_MSS_ERROR = -1,
|
||||
US_MSS_BUSY = -2,
|
||||
US_MSS_NO_CLIENT = -3,
|
||||
} us_mss_lock_result_e;
|
||||
|
||||
|
||||
us_mss_lock_result_e us_memsink_server_x_lock(
|
||||
us_memsink_s *sink,
|
||||
us_memsink_wants_s *w_get);
|
||||
|
||||
bool us_memsink_server_x_is_consumed(us_memsink_s *sink);
|
||||
void us_memsink_server_x_set_consumed(us_memsink_s *sink);
|
||||
|
||||
int us_memsink_server_x_put(us_memsink_s *sink, const us_frame_s *frame);
|
||||
|
||||
int us_memsink_server_x_unlock(us_memsink_s *sink);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "tools.h"
|
||||
|
||||
|
||||
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) {
|
||||
us_memsink_shared_s *us_memsinksh_map(int fd, uz data_size) {
|
||||
us_memsink_shared_s *mem = mmap(
|
||||
NULL,
|
||||
sizeof(us_memsink_shared_s) + data_size,
|
||||
@@ -44,12 +44,12 @@ us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size) {
|
||||
return mem;
|
||||
}
|
||||
|
||||
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size) {
|
||||
int us_memsinksh_unmap(us_memsink_shared_s *mem, uz data_size) {
|
||||
US_A(mem != NULL);
|
||||
return munmap(mem, sizeof(us_memsink_shared_s) + data_size);
|
||||
}
|
||||
|
||||
uz us_memsink_calculate_size(const char *obj) {
|
||||
uz us_memsinksh_calculate_size(const char *obj) {
|
||||
const char *ptr = strrchr(obj, ':');
|
||||
if (ptr == NULL) {
|
||||
ptr = strrchr(obj, '.');
|
||||
@@ -67,6 +67,13 @@ uz us_memsink_calculate_size(const char *obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 *us_memsink_get_data(us_memsink_shared_s *mem) {
|
||||
u8 *us_memsinksh_get_data(us_memsink_shared_s *mem) {
|
||||
return (u8*)(mem) + sizeof(us_memsink_shared_s);
|
||||
}
|
||||
|
||||
bool us_memsinksh_has_clients(us_memsink_shared_s *mem, u32 ttl) {
|
||||
return (
|
||||
mem->client_magic == US_MEMSINK_MAGIC
|
||||
&& mem->last_client_ts + ttl > us_get_now_monotonic()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
#define US_MEMSINK_MAGIC ((u64)0xCAFEBABECAFEBABE)
|
||||
#define US_MEMSINK_VERSION ((u32)10)
|
||||
#define US_MEMSINK_VERSION ((u32)11)
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -44,6 +44,7 @@ typedef struct {
|
||||
u64 id;
|
||||
uz used;
|
||||
|
||||
u64 client_magic;
|
||||
ldf last_client_ts;
|
||||
us_memsink_wants_s wants;
|
||||
|
||||
@@ -51,8 +52,9 @@ typedef struct {
|
||||
} us_memsink_shared_s;
|
||||
|
||||
|
||||
us_memsink_shared_s *us_memsink_shared_map(int fd, uz data_size);
|
||||
int us_memsink_shared_unmap(us_memsink_shared_s *mem, uz data_size);
|
||||
us_memsink_shared_s *us_memsinksh_map(int fd, uz data_size);
|
||||
int us_memsinksh_unmap(us_memsink_shared_s *mem, uz data_size);
|
||||
|
||||
uz us_memsink_calculate_size(const char *obj);
|
||||
u8 *us_memsink_get_data(us_memsink_shared_s *mem);
|
||||
uz us_memsinksh_calculate_size(const char *obj);
|
||||
u8 *us_memsinksh_get_data(us_memsink_shared_s *mem);
|
||||
bool us_memsinksh_has_clients(us_memsink_shared_s *mem, u32 ttl);
|
||||
|
||||
Reference in New Issue
Block a user