mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-03-16 20:43:42 +00:00
refactoring
This commit is contained in:
10
Makefile
10
Makefile
@@ -36,7 +36,7 @@ _USTR_SRCS = $(shell ls \
|
|||||||
_REC_LIBS = $(_COMMON_LIBS) -lrt -lbcm_host -lvcos -lmmal -lmmal_core -lmmal_util -lmmal_vc_client -lmmal_components -L$(RPI_VC_LIBS)
|
_REC_LIBS = $(_COMMON_LIBS) -lrt -lbcm_host -lvcos -lmmal -lmmal_core -lmmal_util -lmmal_vc_client -lmmal_components -L$(RPI_VC_LIBS)
|
||||||
_REC_SRCS = $(shell ls \
|
_REC_SRCS = $(shell ls \
|
||||||
src/libs/common/*.c \
|
src/libs/common/*.c \
|
||||||
src/libs/rawsink/*.c \
|
src/libs/memsink/*.c \
|
||||||
src/libs/h264/*.c \
|
src/libs/h264/*.c \
|
||||||
src/recorder/*.c \
|
src/recorder/*.c \
|
||||||
)
|
)
|
||||||
@@ -47,10 +47,10 @@ $(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
|
|
||||||
ifneq ($(call optbool,$(WITH_RAWSINK)),)
|
ifneq ($(call optbool,$(WITH_MEMSINK)),)
|
||||||
_USTR_LIBS += -lrt
|
_USTR_LIBS += -lrt
|
||||||
override CFLAGS += -DWITH_RAWSINK
|
override CFLAGS += -DWITH_MEMSINK
|
||||||
_USTR_SRCS += $(shell ls src/libs/rawsink/*.c)
|
_USTR_SRCS += $(shell ls src/libs/memsink/*.c)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ override CFLAGS += -DWITH_SETPROCTITLE
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
ifneq ($(call optbool,$(WITH_RAWSINK)),)
|
ifneq ($(call optbool,$(WITH_MEMSINK)),)
|
||||||
ifneq ($(call optbool,$(WITH_OMX)),)
|
ifneq ($(call optbool,$(WITH_OMX)),)
|
||||||
_ENABLE_REC = 1
|
_ENABLE_REC = 1
|
||||||
endif
|
endif
|
||||||
|
|||||||
247
src/libs/memsink/memsink.c
Normal file
247
src/libs/memsink/memsink.c
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
# #
|
||||||
|
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2018 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 "memsink.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int _sem_timedwait_monotonic(sem_t *sem, long double timeout);
|
||||||
|
static int _flock_timedwait_monotonic(int fd, long double timeout);
|
||||||
|
|
||||||
|
|
||||||
|
memsink_s *memsink_open(const char *role, const char *name, bool server, mode_t mode, bool rm, unsigned timeout) {
|
||||||
|
memsink_s *memsink;
|
||||||
|
int flags = (server ? O_RDWR | O_CREAT : O_RDWR);
|
||||||
|
|
||||||
|
A_CALLOC(memsink, 1);
|
||||||
|
memsink->role = role;
|
||||||
|
memsink->server = server;
|
||||||
|
memsink->rm = rm;
|
||||||
|
memsink->timeout = timeout;
|
||||||
|
memsink->fd = -1;
|
||||||
|
memsink->mem = MAP_FAILED;
|
||||||
|
memsink->sig_sem = SEM_FAILED;
|
||||||
|
|
||||||
|
A_CALLOC(memsink->mem_name, strlen(name) + 8);
|
||||||
|
A_CALLOC(memsink->sig_name, strlen(name) + 8);
|
||||||
|
|
||||||
|
sprintf(memsink->mem_name, "%s.mem", name);
|
||||||
|
sprintf(memsink->sig_name, "%s.sig", name);
|
||||||
|
|
||||||
|
LOG_INFO("Using %s sink: %s.{mem,sig}", role, name);
|
||||||
|
|
||||||
|
# define OPEN_SIGNAL { \
|
||||||
|
if ((memsink->sig_sem = sem_open(memsink->sig_name, flags, mode, 0)) == SEM_FAILED) { \
|
||||||
|
LOG_PERROR("Can't open %s sink signal semaphore", role); \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!server) {
|
||||||
|
OPEN_SIGNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Shared memory
|
||||||
|
if ((memsink->fd = shm_open(memsink->mem_name, flags, mode)) == -1) {
|
||||||
|
LOG_PERROR("Can't open %s sink memory", role);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memsink->server && ftruncate(memsink->fd, sizeof(memsink_shared_s)) < 0) {
|
||||||
|
LOG_PERROR("Can't truncate %s sink memory", role);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((memsink->mem = mmap(
|
||||||
|
NULL,
|
||||||
|
sizeof(memsink_shared_s),
|
||||||
|
PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED,
|
||||||
|
memsink->fd,
|
||||||
|
0
|
||||||
|
)) == MAP_FAILED) {
|
||||||
|
LOG_PERROR("Can't mmap %s sink memory", role);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server) {
|
||||||
|
OPEN_SIGNAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
# undef OPEN_SIGNAL
|
||||||
|
|
||||||
|
return memsink;
|
||||||
|
|
||||||
|
error:
|
||||||
|
memsink_close(memsink);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void memsink_close(memsink_s *memsink) {
|
||||||
|
if (memsink->sig_sem != SEM_FAILED) {
|
||||||
|
if (sem_close(memsink->sig_sem) < 0) {
|
||||||
|
LOG_PERROR("Can't close %s sink signal semaphore", memsink->role);
|
||||||
|
}
|
||||||
|
if (memsink->rm && sem_unlink(memsink->sig_name) < 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
LOG_PERROR("Can't remove %s sink signal semaphore", memsink->role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memsink->mem != MAP_FAILED) {
|
||||||
|
if (munmap(memsink->mem, sizeof(memsink_shared_s)) < 0) {
|
||||||
|
LOG_PERROR("Can't unmap %s sink memory", memsink->role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memsink->fd >= 0) {
|
||||||
|
if (close(memsink->fd) < 0) {
|
||||||
|
LOG_PERROR("Can't close %s sink fd", memsink->role);
|
||||||
|
}
|
||||||
|
if (memsink->rm && shm_unlink(memsink->mem_name) < 0) {
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
LOG_PERROR("Can't remove %s sink memory", memsink->role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(memsink->sig_name);
|
||||||
|
free(memsink->mem_name);
|
||||||
|
free(memsink);
|
||||||
|
}
|
||||||
|
|
||||||
|
int memsink_server_put(memsink_s *memsink, frame_s *frame) {
|
||||||
|
long double now = get_now_monotonic();
|
||||||
|
|
||||||
|
assert(memsink->server);
|
||||||
|
|
||||||
|
if (frame->used > MEMSINK_MAX_DATA) {
|
||||||
|
LOG_ERROR("%s sink: Can't put frame: is too big (%zu > %zu)",
|
||||||
|
memsink->role, frame->used, MEMSINK_MAX_DATA);
|
||||||
|
return 0; // -2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_flock_timedwait_monotonic(memsink->fd, 1) == 0) {
|
||||||
|
LOG_PERF("%s sink: >>>>> Exposing new frame ...", memsink->role);
|
||||||
|
|
||||||
|
if (sem_trywait(memsink->sig_sem) < 0 && errno != EAGAIN) {
|
||||||
|
LOG_PERROR("%s sink: Can't wait signal semaphore", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# define COPY(_field) memsink->mem->_field = frame->_field
|
||||||
|
COPY(used);
|
||||||
|
COPY(width);
|
||||||
|
COPY(height);
|
||||||
|
COPY(format);
|
||||||
|
COPY(online);
|
||||||
|
COPY(grab_ts);
|
||||||
|
COPY(encode_begin_ts);
|
||||||
|
COPY(encode_end_ts);
|
||||||
|
memcpy(memsink->mem->data, frame->data, frame->used);
|
||||||
|
# undef COPY
|
||||||
|
|
||||||
|
if (sem_post(memsink->sig_sem) < 0) {
|
||||||
|
LOG_PERROR("%s sink: Can't post signal semaphore", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (flock(memsink->fd, LOCK_UN) < 0) {
|
||||||
|
LOG_PERROR("%s sink: Can't unlock memory", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
LOG_VERBOSE("%s sink: Exposed new frame; full exposition time = %Lf",
|
||||||
|
memsink->role, get_now_monotonic() - now);
|
||||||
|
|
||||||
|
} else if (errno == EWOULDBLOCK) {
|
||||||
|
LOG_PERF("%s sink: ===== Shared memory is busy now; frame skipped", memsink->role);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LOG_PERROR("%s sink: Can't lock memory", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memsink_client_get(memsink_s *memsink, frame_s *frame) { // cppcheck-suppress unusedFunction
|
||||||
|
assert(!memsink->server); // Client only
|
||||||
|
|
||||||
|
if (_sem_timedwait_monotonic(memsink->sig_sem, memsink->timeout) < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
LOG_PERROR("%s src: Can't wait signal semaphore", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_flock_timedwait_monotonic(memsink->fd, memsink->timeout) < 0) {
|
||||||
|
if (errno == EWOULDBLOCK) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
LOG_PERROR("%s src: Can't lock memory", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# define COPY(_field) frame->_field = memsink->mem->_field
|
||||||
|
COPY(width);
|
||||||
|
COPY(height);
|
||||||
|
COPY(format);
|
||||||
|
COPY(online);
|
||||||
|
COPY(grab_ts);
|
||||||
|
COPY(encode_begin_ts);
|
||||||
|
COPY(encode_end_ts);
|
||||||
|
frame_set_data(frame, memsink->mem->data, memsink->mem->used);
|
||||||
|
# undef COPY
|
||||||
|
|
||||||
|
if (flock(memsink->fd, LOCK_UN) < 0) {
|
||||||
|
LOG_PERROR("%s src: Can't unlock memory", memsink->role);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sem_timedwait_monotonic(sem_t *sem, long double timeout) {
|
||||||
|
long double deadline_ts = get_now_monotonic() + timeout;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
retval = sem_trywait(sem);
|
||||||
|
if (retval == 0 || errno != EAGAIN || get_now_monotonic() > deadline_ts) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _flock_timedwait_monotonic(int fd, long double timeout) {
|
||||||
|
long double deadline_ts = get_now_monotonic() + timeout;
|
||||||
|
int retval = -1;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
retval = flock(fd, LOCK_EX | LOCK_NB);
|
||||||
|
if (retval == 0 || errno != EWOULDBLOCK || get_now_monotonic() > deadline_ts) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
@@ -40,10 +40,10 @@
|
|||||||
#include "../common/frame.h"
|
#include "../common/frame.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef CFG_RAWSINK_MAX_DATA
|
#ifndef CFG_MEMSINK_MAX_DATA
|
||||||
# define CFG_RAWSINK_MAX_DATA 33554432
|
# define CFG_MEMSINK_MAX_DATA 33554432
|
||||||
#endif
|
#endif
|
||||||
#define RAWSINK_MAX_DATA ((size_t)(CFG_RAWSINK_MAX_DATA))
|
#define MEMSINK_MAX_DATA ((size_t)(CFG_MEMSINK_MAX_DATA))
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -53,10 +53,13 @@ typedef struct {
|
|||||||
unsigned format;
|
unsigned format;
|
||||||
bool online;
|
bool online;
|
||||||
long double grab_ts;
|
long double grab_ts;
|
||||||
uint8_t data[RAWSINK_MAX_DATA];
|
long double encode_begin_ts;
|
||||||
} rawsink_shared_s;
|
long double encode_end_ts;
|
||||||
|
uint8_t data[MEMSINK_MAX_DATA];
|
||||||
|
} memsink_shared_s;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
const char *role;
|
||||||
bool server;
|
bool server;
|
||||||
bool rm;
|
bool rm;
|
||||||
unsigned timeout;
|
unsigned timeout;
|
||||||
@@ -65,13 +68,13 @@ typedef struct {
|
|||||||
char *sig_name;
|
char *sig_name;
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
rawsink_shared_s *mem;
|
memsink_shared_s *mem;
|
||||||
sem_t *sig_sem;
|
sem_t *sig_sem;
|
||||||
} rawsink_s;
|
} memsink_s;
|
||||||
|
|
||||||
|
|
||||||
rawsink_s *rawsink_open(const char *name, bool server, mode_t mode, bool rm, unsigned timeout);
|
memsink_s *memsink_open(const char *role, const char *name, bool server, mode_t mode, bool rm, unsigned timeout);
|
||||||
void rawsink_close(rawsink_s *rawsink);
|
void memsink_close(memsink_s *memsink);
|
||||||
|
|
||||||
int rawsink_server_put(rawsink_s *rawsink, frame_s *frame);
|
int memsink_server_put(memsink_s *memsink, frame_s *frame);
|
||||||
int rawsink_client_get(rawsink_s *rawsink, frame_s *frame);
|
int memsink_client_get(memsink_s *memsink, frame_s *frame);
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
# #
|
|
||||||
# uStreamer - Lightweight and fast MJPG-HTTP streamer. #
|
|
||||||
# #
|
|
||||||
# Copyright (C) 2018 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 "rawsink.h"
|
|
||||||
|
|
||||||
|
|
||||||
static int _sem_timedwait_monotonic(sem_t *sem, long double timeout);
|
|
||||||
static int _flock_timedwait_monotonic(int fd, long double timeout);
|
|
||||||
|
|
||||||
|
|
||||||
rawsink_s *rawsink_open(const char *name, bool server, mode_t mode, bool rm, unsigned timeout) {
|
|
||||||
rawsink_s *rawsink;
|
|
||||||
int flags = (server ? O_RDWR | O_CREAT : O_RDWR);
|
|
||||||
|
|
||||||
A_CALLOC(rawsink, 1);
|
|
||||||
rawsink->server = server;
|
|
||||||
rawsink->rm = rm;
|
|
||||||
rawsink->timeout = timeout;
|
|
||||||
rawsink->fd = -1;
|
|
||||||
rawsink->mem = MAP_FAILED;
|
|
||||||
rawsink->sig_sem = SEM_FAILED;
|
|
||||||
|
|
||||||
A_CALLOC(rawsink->mem_name, strlen(name) + 8);
|
|
||||||
A_CALLOC(rawsink->sig_name, strlen(name) + 8);
|
|
||||||
|
|
||||||
sprintf(rawsink->mem_name, "%s.mem", name);
|
|
||||||
sprintf(rawsink->sig_name, "%s.sig", name);
|
|
||||||
|
|
||||||
LOG_INFO("Using RAW sink: %s.{mem,sig}", name);
|
|
||||||
|
|
||||||
# define OPEN_SIGNAL { \
|
|
||||||
if ((rawsink->sig_sem = sem_open(rawsink->sig_name, flags, mode, 0)) == SEM_FAILED) { \
|
|
||||||
LOG_PERROR("Can't open RAW sink signal semaphore"); \
|
|
||||||
goto error; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!server) {
|
|
||||||
OPEN_SIGNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Shared memory
|
|
||||||
if ((rawsink->fd = shm_open(rawsink->mem_name, flags, mode)) == -1) {
|
|
||||||
LOG_PERROR("Can't open RAW sink memory");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawsink->server && ftruncate(rawsink->fd, sizeof(rawsink_shared_s)) < 0) {
|
|
||||||
LOG_PERROR("Can't truncate RAW sink memory");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((rawsink->mem = mmap(
|
|
||||||
NULL,
|
|
||||||
sizeof(rawsink_shared_s),
|
|
||||||
PROT_READ | PROT_WRITE,
|
|
||||||
MAP_SHARED,
|
|
||||||
rawsink->fd,
|
|
||||||
0
|
|
||||||
)) == MAP_FAILED) {
|
|
||||||
LOG_PERROR("Can't mmap RAW sink memory");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (server) {
|
|
||||||
OPEN_SIGNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
# undef OPEN_SIGNAL
|
|
||||||
|
|
||||||
return rawsink;
|
|
||||||
|
|
||||||
error:
|
|
||||||
rawsink_close(rawsink);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rawsink_close(rawsink_s *rawsink) {
|
|
||||||
if (rawsink->sig_sem != SEM_FAILED) {
|
|
||||||
if (sem_close(rawsink->sig_sem) < 0) {
|
|
||||||
LOG_PERROR("Can't close RAW sink signal semaphore");
|
|
||||||
}
|
|
||||||
if (rawsink->rm && sem_unlink(rawsink->sig_name) < 0) {
|
|
||||||
if (errno != ENOENT) {
|
|
||||||
LOG_PERROR("Can't remove RAW sink signal semaphore");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawsink->mem != MAP_FAILED) {
|
|
||||||
if (munmap(rawsink->mem, sizeof(rawsink_shared_s)) < 0) {
|
|
||||||
LOG_PERROR("Can't unmap RAW sink memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawsink->fd >= 0) {
|
|
||||||
if (close(rawsink->fd) < 0) {
|
|
||||||
LOG_PERROR("Can't close RAW sink fd");
|
|
||||||
}
|
|
||||||
if (rawsink->rm && shm_unlink(rawsink->mem_name) < 0) {
|
|
||||||
if (errno != ENOENT) {
|
|
||||||
LOG_PERROR("Can't remove RAW sink memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(rawsink->sig_name);
|
|
||||||
free(rawsink->mem_name);
|
|
||||||
free(rawsink);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rawsink_server_put(rawsink_s *rawsink, frame_s *frame) {
|
|
||||||
long double now = get_now_monotonic();
|
|
||||||
|
|
||||||
assert(rawsink->server);
|
|
||||||
|
|
||||||
if (frame->used > RAWSINK_MAX_DATA) {
|
|
||||||
LOG_ERROR("RAWSINK: Can't put RAW frame: is too big (%zu > %zu)", frame->used, RAWSINK_MAX_DATA);
|
|
||||||
return 0; // -2
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_flock_timedwait_monotonic(rawsink->fd, 1) == 0) {
|
|
||||||
LOG_PERF("RAWSINK: >>>>> Exposing new frame ...");
|
|
||||||
|
|
||||||
if (sem_trywait(rawsink->sig_sem) < 0 && errno != EAGAIN) {
|
|
||||||
LOG_PERROR("RAWSINK: Can't wait signal semaphore");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
# define COPY(_field) rawsink->mem->_field = frame->_field
|
|
||||||
COPY(used);
|
|
||||||
COPY(width);
|
|
||||||
COPY(height);
|
|
||||||
COPY(format);
|
|
||||||
COPY(online);
|
|
||||||
COPY(grab_ts);
|
|
||||||
memcpy(rawsink->mem->data, frame->data, frame->used);
|
|
||||||
# undef COPY
|
|
||||||
|
|
||||||
if (sem_post(rawsink->sig_sem) < 0) {
|
|
||||||
LOG_PERROR("RAWSINK: Can't post signal semaphore");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (flock(rawsink->fd, LOCK_UN) < 0) {
|
|
||||||
LOG_PERROR("RAWSINK: Can't unlock memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
LOG_VERBOSE("RAWSINK: Exposed new frame; full exposition time = %Lf", get_now_monotonic() - now);
|
|
||||||
|
|
||||||
} else if (errno == EWOULDBLOCK) {
|
|
||||||
LOG_PERF("RAWSINK: ===== Shared memory is busy now; frame skipped");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
LOG_PERROR("RAWSINK: Can't lock memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rawsink_client_get(rawsink_s *rawsink, frame_s *frame) { // cppcheck-suppress unusedFunction
|
|
||||||
assert(!rawsink->server); // Client only
|
|
||||||
|
|
||||||
if (_sem_timedwait_monotonic(rawsink->sig_sem, rawsink->timeout) < 0) {
|
|
||||||
if (errno == EAGAIN) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
LOG_PERROR("RAWSRC: Can't wait signal semaphore");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (_flock_timedwait_monotonic(rawsink->fd, rawsink->timeout) < 0) {
|
|
||||||
if (errno == EWOULDBLOCK) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
LOG_PERROR("RAWSRC: Can't lock memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
# define COPY(_field) frame->_field = rawsink->mem->_field
|
|
||||||
COPY(width);
|
|
||||||
COPY(height);
|
|
||||||
COPY(format);
|
|
||||||
COPY(online);
|
|
||||||
COPY(grab_ts);
|
|
||||||
frame_set_data(frame, rawsink->mem->data, rawsink->mem->used);
|
|
||||||
# undef COPY
|
|
||||||
|
|
||||||
if (flock(rawsink->fd, LOCK_UN) < 0) {
|
|
||||||
LOG_PERROR("RAWSRC: Can't unlock memory");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _sem_timedwait_monotonic(sem_t *sem, long double timeout) {
|
|
||||||
long double deadline_ts = get_now_monotonic() + timeout;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
retval = sem_trywait(sem);
|
|
||||||
if (retval == 0 || errno != EAGAIN || get_now_monotonic() > deadline_ts) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _flock_timedwait_monotonic(int fd, long double timeout) {
|
|
||||||
long double deadline_ts = get_now_monotonic() + timeout;
|
|
||||||
int retval = -1;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
retval = flock(fd, LOCK_EX | LOCK_NB);
|
|
||||||
if (retval == 0 || errno != EWOULDBLOCK || get_now_monotonic() > deadline_ts) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
usleep(1000);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../common/logging.h"
|
#include "../common/logging.h"
|
||||||
#include "../common/frame.h"
|
#include "../common/frame.h"
|
||||||
#include "../rawsink/rawsink.h"
|
#include "../memsink/memsink.h"
|
||||||
#include "../h264/encoder.h"
|
#include "../h264/encoder.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
@@ -11,12 +11,12 @@ int main(void) {
|
|||||||
frame_s *src = frame_init("src");
|
frame_s *src = frame_init("src");
|
||||||
frame_s *dest = frame_init("dest");
|
frame_s *dest = frame_init("dest");
|
||||||
h264_encoder_s *encoder = h264_encoder_init();
|
h264_encoder_s *encoder = h264_encoder_init();
|
||||||
rawsink_s *rawsink = rawsink_init("test", false, 0, 0, (long double)encoder->fps / (long double)encoder->gop);
|
memsink_s *memsink = memsink_init("RAW", "test", false, 0, 0, (long double)encoder->fps / (long double)encoder->gop);
|
||||||
FILE *fp = fopen("test.h264", "wb");
|
FILE *fp = fopen("test.h264", "wb");
|
||||||
|
|
||||||
if (rawsink) {
|
if (memsink) {
|
||||||
int error = 0;
|
int error = 0;
|
||||||
while ((error = rawsink_client_get(rawsink, src)) != -1) {
|
while ((error = memsink_client_get(memsink, src)) != -1) {
|
||||||
if (error == 0 /*|| (error == -2 && src->used > 0)*/) {
|
if (error == 0 /*|| (error == -2 && src->used > 0)*/) {
|
||||||
if (!h264_encoder_compress(encoder, src, dest, false)) {
|
if (!h264_encoder_compress(encoder, src, dest, false)) {
|
||||||
LOG_INFO("frame %Lf", get_now_monotonic() - dest->grab_ts);
|
LOG_INFO("frame %Lf", get_now_monotonic() - dest->grab_ts);
|
||||||
|
|||||||
@@ -48,8 +48,8 @@
|
|||||||
|
|
||||||
#include "xioctl.h"
|
#include "xioctl.h"
|
||||||
|
|
||||||
#ifdef WITH_RAWSINK
|
#ifdef WITH_MEMSINK
|
||||||
# include "../libs/rawsink/rawsink.h"
|
# include "../libs/memsink/memsink.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,11 +82,11 @@ enum _OPT_VALUES {
|
|||||||
_O_TCP_NODELAY,
|
_O_TCP_NODELAY,
|
||||||
_O_SERVER_TIMEOUT,
|
_O_SERVER_TIMEOUT,
|
||||||
|
|
||||||
#ifdef WITH_RAWSINK
|
#ifdef WITH_MEMSINK
|
||||||
_O_RAWSINK,
|
_O_RAW_SINK,
|
||||||
_O_RAWSINK_MODE,
|
_O_RAW_SINK_MODE,
|
||||||
_O_RAWSINK_RM,
|
_O_RAW_SINK_RM,
|
||||||
_O_RAWSINK_TIMEOUT,
|
_O_RAW_SINK_TIMEOUT,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_GPIO
|
#ifdef WITH_GPIO
|
||||||
@@ -167,11 +167,11 @@ static const struct option _LONG_OPTS[] = {
|
|||||||
{"tcp-nodelay", no_argument, NULL, _O_TCP_NODELAY},
|
{"tcp-nodelay", no_argument, NULL, _O_TCP_NODELAY},
|
||||||
{"server-timeout", required_argument, NULL, _O_SERVER_TIMEOUT},
|
{"server-timeout", required_argument, NULL, _O_SERVER_TIMEOUT},
|
||||||
|
|
||||||
#ifdef WITH_RAWSINK
|
#ifdef WITH_MEMSINK
|
||||||
{"raw-sink", required_argument, NULL, _O_RAWSINK},
|
{"raw-sink", required_argument, NULL, _O_RAW_SINK},
|
||||||
{"raw-sink-mode", required_argument, NULL, _O_RAWSINK_MODE},
|
{"raw-sink-mode", required_argument, NULL, _O_RAW_SINK_MODE},
|
||||||
{"raw-sink-rm", no_argument, NULL, _O_RAWSINK_RM},
|
{"raw-sink-rm", no_argument, NULL, _O_RAW_SINK_RM},
|
||||||
{"raw-sink-timeout", required_argument, NULL, _O_RAWSINK_TIMEOUT},
|
{"raw-sink-timeout", required_argument, NULL, _O_RAW_SINK_TIMEOUT},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_GPIO
|
#ifdef WITH_GPIO
|
||||||
@@ -230,9 +230,9 @@ options_s *options_init(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void options_destroy(options_s *options) {
|
void options_destroy(options_s *options) {
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
if (options->rawsink) {
|
if (options->raw_sink) {
|
||||||
rawsink_close(options->rawsink);
|
memsink_close(options->raw_sink);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
if (options->blank) {
|
if (options->blank) {
|
||||||
@@ -320,11 +320,11 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
|
|||||||
|
|
||||||
char *blank_path = NULL;
|
char *blank_path = NULL;
|
||||||
|
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
char *rawsink_name = NULL;
|
char *raw_sink_name = NULL;
|
||||||
mode_t rawsink_mode = 0660;
|
mode_t raw_sink_mode = 0660;
|
||||||
bool rawsink_rm = false;
|
bool raw_sink_rm = false;
|
||||||
unsigned rawsink_timeout = 1;
|
unsigned raw_sink_timeout = 1;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_SETPROCTITLE
|
# ifdef WITH_SETPROCTITLE
|
||||||
@@ -415,11 +415,11 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
|
|||||||
case _O_TCP_NODELAY: OPT_SET(server->tcp_nodelay, true);
|
case _O_TCP_NODELAY: OPT_SET(server->tcp_nodelay, true);
|
||||||
case _O_SERVER_TIMEOUT: OPT_NUMBER("--server-timeout", server->timeout, 1, 60, 0);
|
case _O_SERVER_TIMEOUT: OPT_NUMBER("--server-timeout", server->timeout, 1, 60, 0);
|
||||||
|
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
case _O_RAWSINK: OPT_SET(rawsink_name, optarg);
|
case _O_RAW_SINK: OPT_SET(raw_sink_name, optarg);
|
||||||
case _O_RAWSINK_MODE: OPT_NUMBER("--raw-sink-mode", rawsink_mode, INT_MIN, INT_MAX, 8);
|
case _O_RAW_SINK_MODE: OPT_NUMBER("--raw-sink-mode", raw_sink_mode, INT_MIN, INT_MAX, 8);
|
||||||
case _O_RAWSINK_RM: OPT_SET(rawsink_rm, true);
|
case _O_RAW_SINK_RM: OPT_SET(raw_sink_rm, true);
|
||||||
case _O_RAWSINK_TIMEOUT: OPT_NUMBER("--raw-sink-timeout", rawsink_timeout, 1, 60, 0);
|
case _O_RAW_SINK_TIMEOUT: OPT_NUMBER("--raw-sink-timeout", raw_sink_timeout, 1, 60, 0);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
@@ -461,17 +461,18 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
|
|||||||
options->blank = blank_frame_init(blank_path);
|
options->blank = blank_frame_init(blank_path);
|
||||||
stream->blank = options->blank;
|
stream->blank = options->blank;
|
||||||
|
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
if (rawsink_name && rawsink_name[0] != '\0') {
|
if (raw_sink_name && raw_sink_name[0] != '\0') {
|
||||||
options->rawsink = rawsink_open(
|
options->raw_sink = memsink_open(
|
||||||
rawsink_name,
|
"RAW",
|
||||||
|
raw_sink_name,
|
||||||
true,
|
true,
|
||||||
rawsink_mode,
|
raw_sink_mode,
|
||||||
rawsink_rm,
|
raw_sink_rm,
|
||||||
rawsink_timeout
|
raw_sink_timeout
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
stream->rawsink = options->rawsink;
|
stream->raw_sink = options->raw_sink;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_SETPROCTITLE
|
# ifdef WITH_SETPROCTITLE
|
||||||
@@ -567,10 +568,10 @@ static void _features(void) {
|
|||||||
puts("- WITH_OMX");
|
puts("- WITH_OMX");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
puts("+ WITH_RAWSINK");
|
puts("+ WITH_MEMSINK");
|
||||||
# else
|
# else
|
||||||
puts("- WITH_RAWSINK");
|
puts("- WITH_MEMSINK");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
@@ -639,7 +640,7 @@ static void _help(device_s *dev, encoder_s *encoder, stream_s *stream, server_s
|
|||||||
printf(" * OMX ── GPU hardware accelerated MJPG encoding with OpenMax;\n");
|
printf(" * OMX ── GPU hardware accelerated MJPG encoding with OpenMax;\n");
|
||||||
# endif
|
# endif
|
||||||
printf(" * HW ─── Use pre-encoded MJPG frames directly from camera hardware.\n");
|
printf(" * HW ─── Use pre-encoded MJPG frames directly from camera hardware.\n");
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
printf(" * NOOP ─ Don't compress stream. Useful for the RAW sink.\n\n");
|
printf(" * NOOP ─ Don't compress stream. Useful for the RAW sink.\n\n");
|
||||||
# endif
|
# endif
|
||||||
# ifdef WITH_OMX
|
# ifdef WITH_OMX
|
||||||
@@ -693,7 +694,7 @@ static void _help(device_s *dev, encoder_s *encoder, stream_s *stream, server_s
|
|||||||
printf(" Default: disabled.\n\n");
|
printf(" Default: disabled.\n\n");
|
||||||
printf(" --allow-origin <str> ─────── Set Access-Control-Allow-Origin header. Default: disabled.\n\n");
|
printf(" --allow-origin <str> ─────── Set Access-Control-Allow-Origin header. Default: disabled.\n\n");
|
||||||
printf(" --server-timeout <sec> ───── Timeout for client connections. Default: %u.\n\n", server->timeout);
|
printf(" --server-timeout <sec> ───── Timeout for client connections. Default: %u.\n\n", server->timeout);
|
||||||
#ifdef WITH_RAWSINK
|
#ifdef WITH_MEMSINK
|
||||||
printf("RAW sink options:\n");
|
printf("RAW sink options:\n");
|
||||||
printf("═════════════════\n");
|
printf("═════════════════\n");
|
||||||
printf(" --raw-sink <name> ──────── Use the shared memory to sink RAW frames before encoding.\n");
|
printf(" --raw-sink <name> ──────── Use the shared memory to sink RAW frames before encoding.\n");
|
||||||
|
|||||||
@@ -37,8 +37,8 @@
|
|||||||
#include "../libs/common/logging.h"
|
#include "../libs/common/logging.h"
|
||||||
#include "../libs/common/process.h"
|
#include "../libs/common/process.h"
|
||||||
#include "../libs/common/frame.h"
|
#include "../libs/common/frame.h"
|
||||||
#ifdef WITH_RAWSINK
|
#ifdef WITH_MEMSINK
|
||||||
# include "../libs/rawsink/rawsink.h"
|
# include "../libs/memsink/memsink.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@@ -56,8 +56,8 @@ typedef struct {
|
|||||||
char **argv;
|
char **argv;
|
||||||
char **argv_copy;
|
char **argv_copy;
|
||||||
frame_s *blank;
|
frame_s *blank;
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
rawsink_s *rawsink;
|
memsink_s *raw_sink;
|
||||||
# endif
|
# endif
|
||||||
} options_s;
|
} options_s;
|
||||||
|
|
||||||
|
|||||||
@@ -208,9 +208,9 @@ void stream_loop(stream_s *stream) {
|
|||||||
grab_after = now + fluency_delay;
|
grab_after = now + fluency_delay;
|
||||||
LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after);
|
LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after);
|
||||||
|
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
if (stream->rawsink && rawsink_server_put(stream->rawsink, &DEV(run->hw_buffers[buf_index].raw)) < 0) {
|
if (stream->raw_sink && memsink_server_put(stream->raw_sink, &DEV(run->hw_buffers[buf_index].raw)) < 0) {
|
||||||
stream->rawsink = NULL;
|
stream->raw_sink = NULL;
|
||||||
LOG_ERROR("RAW sink completely disabled due error");
|
LOG_ERROR("RAW sink completely disabled due error");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
@@ -264,9 +264,9 @@ static _pool_s *_stream_init_loop(stream_s *stream) {
|
|||||||
|
|
||||||
while (!atomic_load(&stream->proc->stop)) {
|
while (!atomic_load(&stream->proc->stop)) {
|
||||||
if (_stream_expose_frame(stream, NULL, 0)) {
|
if (_stream_expose_frame(stream, NULL, 0)) {
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
if (stream->rawsink && rawsink_server_put(stream->rawsink, stream->blank) < 0) {
|
if (stream->raw_sink && memsink_server_put(stream->raw_sink, stream->blank) < 0) {
|
||||||
stream->rawsink = NULL;
|
stream->raw_sink = NULL;
|
||||||
LOG_ERROR("RAW sink completely disabled due error");
|
LOG_ERROR("RAW sink completely disabled due error");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
@@ -40,8 +40,8 @@
|
|||||||
#include "blank.h"
|
#include "blank.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "encoder.h"
|
#include "encoder.h"
|
||||||
#ifdef WITH_RAWSINK
|
#ifdef WITH_MEMSINK
|
||||||
# include "../libs/rawsink/rawsink.h"
|
# include "../libs/memsink/memsink.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_GPIO
|
#ifdef WITH_GPIO
|
||||||
# include "gpio/gpio.h"
|
# include "gpio/gpio.h"
|
||||||
@@ -68,8 +68,8 @@ typedef struct {
|
|||||||
device_s *dev;
|
device_s *dev;
|
||||||
encoder_s *encoder;
|
encoder_s *encoder;
|
||||||
frame_s *blank;
|
frame_s *blank;
|
||||||
# ifdef WITH_RAWSINK
|
# ifdef WITH_MEMSINK
|
||||||
rawsink_s *rawsink;
|
memsink_s *raw_sink;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
process_s *proc;
|
process_s *proc;
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ Set Access\-Control\-Allow\-Origin header. Default: disabled.
|
|||||||
Timeout for client connections. Default: 10.
|
Timeout for client connections. Default: 10.
|
||||||
|
|
||||||
.SS "RAW sink options"
|
.SS "RAW sink options"
|
||||||
Available only if \fBWITH_RAWSINK\fR feature enabled.
|
Available only if \fBWITH_MEMSINK\fR feature enabled.
|
||||||
.TP
|
.TP
|
||||||
.BR \-\-raw\-sink\ \fIname
|
.BR \-\-raw\-sink\ \fIname
|
||||||
Use the specified shared memory object to sink RAW frames before encoding.
|
Use the specified shared memory object to sink RAW frames before encoding.
|
||||||
|
|||||||
Reference in New Issue
Block a user