This commit is contained in:
Devaev Maxim 2021-01-04 12:55:25 +03:00
parent 6eb5e62aae
commit 944bd89b4e
17 changed files with 322 additions and 292 deletions

View File

@ -33,11 +33,10 @@ _USTR_SRCS = $(shell ls \
src/ustreamer/encoders/hw/*.c \
)
_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
_REC_SRCS = $(shell ls \
src/libs/common/*.c \
src/libs/memsink/*.c \
src/libs/h264/*.c \
src/recorder/*.c \
)
@ -47,17 +46,14 @@ $(filter $(shell echo $(1) | tr A-Z a-z), yes on 1)
endef
ifneq ($(call optbool,$(WITH_MEMSINK)),)
_USTR_LIBS += -lrt
override CFLAGS += -DWITH_MEMSINK
_USTR_SRCS += $(shell ls src/libs/memsink/*.c)
endif
ifneq ($(call optbool,$(WITH_OMX)),)
_USTR_LIBS += -lbcm_host -lvcos -lopenmaxil -L$(RPI_VC_LIBS)
_USTR_LIBS += -lrt -lbcm_host -lvcos -lopenmaxil -lmmal -lmmal_core -lmmal_util -lmmal_vc_client -lmmal_components -L$(RPI_VC_LIBS)
override CFLAGS += -DWITH_OMX -DOMX_SKIP64BIT -I$(RPI_VC_HEADERS)
_USTR_SRCS += $(shell ls src/ustreamer/encoders/omx/*.c)
_USTR_SRCS += $(shell ls \
src/libs/memsink/*.c \
src/ustreamer/encoders/omx/*.c \
src/ustreamer/h264/*.c \
)
endif
@ -83,13 +79,6 @@ override CFLAGS += -DWITH_SETPROCTITLE
endif
ifneq ($(call optbool,$(WITH_MEMSINK)),)
ifneq ($(call optbool,$(WITH_OMX)),)
_ENABLE_REC = 1
endif
endif
# =====
all: $(USTR) $(REC)
@ -98,14 +87,14 @@ install: $(USTR) $(REC)
install -Dm755 $(USTR) $(DESTDIR)$(PREFIX)/bin/$(USTR)
install -Dm644 $(USTR).1 $(DESTDIR)$(MANPREFIX)/man1/$(USTR).1
gzip $(DESTDIR)$(MANPREFIX)/man1/$(USTR).1
#ifneq ($(_ENABLE_REC),)
#ifneq ($(call optbool,$(WITH_OMX)),)
# install -Dm755 $(DESTDIR)$(PREFIX)/bin/$(REC)
#endif
install-strip: install
strip $(DESTDIR)$(PREFIX)/bin/$(USTR)
#ifneq ($(_ENABLE_REC),)
#ifneq ($(call optbool,$(WITH_OMX)),)
# strip $(DESTDIR)$(PREFIX)/bin/$(REC)
#endif
@ -113,6 +102,9 @@ install-strip: install
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/$(USTR) \
$(DESTDIR)$(MANPREFIX)/man1/$(USTR).1
#ifneq ($(call optbool,$(WITH_OMX)),)
# rm -f $(DESTDIR)$(PREFIX)/bin/$(REC)
#endif
regen:
@ -121,22 +113,22 @@ regen:
$(USTR): $(_USTR_SRCS:%.c=$(BUILD)/%.o)
$(info -- LD $@)
$(info == LD $@)
@ $(CC) $^ -o $@ $(LDFLAGS) $(_USTR_LIBS)
$(info == CC = $(CC))
$(info == LIBS = $(_USTR_LIBS))
$(info == CFLAGS = $(CFLAGS))
$(info == LDFLAGS = $(LDFLAGS))
$(info :: CC = $(CC))
$(info :: LIBS = $(_USTR_LIBS))
$(info :: CFLAGS = $(CFLAGS))
$(info :: LDFLAGS = $(LDFLAGS))
ifneq ($(_ENABLE_REC),)
ifneq ($(call optbool,$(WITH_OMX)),)
$(REC): $(_REC_SRCS:%.c=$(BUILD)/%.o)
$(info -- LD $@)
$(info == LD $@)
@ $(CC) $^ -o $@ $(LDFLAGS) $(_REC_LIBS)
$(info == CC = $(CC))
$(info == LIBS = $(_REC_LIBS))
$(info == CFLAGS = $(CFLAGS))
$(info == LDFLAGS = $(LDFLAGS))
$(info :: CC = $(CC))
$(info :: LIBS = $(_REC_LIBS))
$(info :: CFLAGS = $(CFLAGS))
$(info :: LDFLAGS = $(LDFLAGS))
else
$(REC):
@ true
@ -193,4 +185,5 @@ clean:
rm -rf pkg/arch/pkg pkg/arch/src pkg/arch/v*.tar.gz pkg/arch/ustreamer-*.pkg.tar.{xz,zst}
rm -rf $(USTR) $(REC) $(BUILD) vgcore.* *.sock
.PHONY: linters

View File

@ -18,7 +18,6 @@ commands = cppcheck \
--suppress=variableScope \
--inline-suppr \
-DCHAR_BIT=8 \
-DWITH_MEMSINK \
-DWITH_OMX \
-DWITH_GPIO \
src

View File

@ -28,27 +28,27 @@ static int _flock_timedwait_monotonic(int fd, long double timeout);
memsink_s *memsink_init(const char *name, const char *prefix, bool server, mode_t mode, bool rm, unsigned timeout) {
memsink_s *memsink;
A_CALLOC(memsink, 1);
memsink->name = name;
memsink->server = server;
memsink->rm = rm;
memsink->timeout = timeout;
memsink->fd = -1;
memsink->mem = MAP_FAILED;
memsink->sig_sem = SEM_FAILED;
memsink_s *sink;
A_CALLOC(sink, 1);
sink->name = name;
sink->server = server;
sink->rm = rm;
sink->timeout = timeout;
sink->fd = -1;
sink->mem = MAP_FAILED;
sink->sig_sem = SEM_FAILED;
A_CALLOC(memsink->mem_name, strlen(prefix) + 8);
A_CALLOC(memsink->sig_name, strlen(prefix) + 8);
A_CALLOC(sink->mem_name, strlen(prefix) + 8);
A_CALLOC(sink->sig_name, strlen(prefix) + 8);
sprintf(memsink->mem_name, "%s.mem", prefix);
sprintf(memsink->sig_name, "%s.sig", prefix);
sprintf(sink->mem_name, "%s.mem", prefix);
sprintf(sink->sig_name, "%s.sig", prefix);
LOG_INFO("Using %s sink: %s.{mem,sig}", name, prefix);
LOG_INFO("Using '%s' sink: %s.{mem,sig}", name, prefix);
const int flags = (server ? O_RDWR | O_CREAT : O_RDWR);
# define OPEN_SIGNAL { \
if ((memsink->sig_sem = sem_open(memsink->sig_name, flags, mode, 0)) == SEM_FAILED) { \
if ((sink->sig_sem = sem_open(sink->sig_name, flags, mode, 0)) == SEM_FAILED) { \
LOG_PERROR("Can't open %s sink signal semaphore", name); \
goto error; \
} \
@ -59,22 +59,22 @@ memsink_s *memsink_init(const char *name, const char *prefix, bool server, mode_
}
{ // Shared memory
if ((memsink->fd = shm_open(memsink->mem_name, flags, mode)) == -1) {
if ((sink->fd = shm_open(sink->mem_name, flags, mode)) == -1) {
LOG_PERROR("Can't open %s sink memory", name);
goto error;
}
if (memsink->server && ftruncate(memsink->fd, sizeof(memsink_shared_s)) < 0) {
if (sink->server && ftruncate(sink->fd, sizeof(memsink_shared_s)) < 0) {
LOG_PERROR("Can't truncate %s sink memory", name);
goto error;
}
if ((memsink->mem = mmap(
if ((sink->mem = mmap(
NULL,
sizeof(memsink_shared_s),
PROT_READ | PROT_WRITE,
MAP_SHARED,
memsink->fd,
sink->fd,
0
)) == MAP_FAILED) {
LOG_PERROR("Can't mmap %s sink memory", name);
@ -88,67 +88,67 @@ memsink_s *memsink_init(const char *name, const char *prefix, bool server, mode_
# undef OPEN_SIGNAL
return memsink;
return sink;
error:
memsink_destroy(memsink);
memsink_destroy(sink);
return NULL;
}
void memsink_destroy(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->name);
void memsink_destroy(memsink_s *sink) {
if (sink->sig_sem != SEM_FAILED) {
if (sem_close(sink->sig_sem) < 0) {
LOG_PERROR("Can't close %s sink signal semaphore", sink->name);
}
if (memsink->rm && sem_unlink(memsink->sig_name) < 0) {
if (sink->rm && sem_unlink(sink->sig_name) < 0) {
if (errno != ENOENT) {
LOG_PERROR("Can't remove %s sink signal semaphore", memsink->name);
LOG_PERROR("Can't remove %s sink signal semaphore", sink->name);
}
}
}
if (memsink->mem != MAP_FAILED) {
if (munmap(memsink->mem, sizeof(memsink_shared_s)) < 0) {
LOG_PERROR("Can't unmap %s sink memory", memsink->name);
if (sink->mem != MAP_FAILED) {
if (munmap(sink->mem, sizeof(memsink_shared_s)) < 0) {
LOG_PERROR("Can't unmap %s sink memory", sink->name);
}
}
if (memsink->fd >= 0) {
if (close(memsink->fd) < 0) {
LOG_PERROR("Can't close %s sink fd", memsink->name);
if (sink->fd >= 0) {
if (close(sink->fd) < 0) {
LOG_PERROR("Can't close %s sink fd", sink->name);
}
if (memsink->rm && shm_unlink(memsink->mem_name) < 0) {
if (sink->rm && shm_unlink(sink->mem_name) < 0) {
if (errno != ENOENT) {
LOG_PERROR("Can't remove %s sink memory", memsink->name);
LOG_PERROR("Can't remove %s sink memory", sink->name);
}
}
}
free(memsink->sig_name);
free(memsink->mem_name);
free(memsink);
free(sink->sig_name);
free(sink->mem_name);
free(sink);
}
int memsink_server_put(memsink_s *memsink, const frame_s *frame) {
assert(memsink->server);
int memsink_server_put(memsink_s *sink, const frame_s *frame) {
assert(sink->server);
const long double now = get_now_monotonic();
if (frame->used > MEMSINK_MAX_DATA) {
LOG_ERROR("%s sink: Can't put frame: is too big (%zu > %zu)",
memsink->name, frame->used, MEMSINK_MAX_DATA);
sink->name, frame->used, MEMSINK_MAX_DATA);
return 0; // -2
}
if (_flock_timedwait_monotonic(memsink->fd, 1) == 0) {
LOG_PERF("%s sink: >>>>> Exposing new frame ...", memsink->name);
if (_flock_timedwait_monotonic(sink->fd, 1) == 0) {
LOG_PERF("%s sink: >>>>> Exposing new frame ...", sink->name);
if (sem_trywait(memsink->sig_sem) < 0 && errno != EAGAIN) {
LOG_PERROR("%s sink: Can't wait signal semaphore", memsink->name);
if (sem_trywait(sink->sig_sem) < 0 && errno != EAGAIN) {
LOG_PERROR("%s sink: Can't wait signal semaphore", sink->name);
return -1;
}
# define COPY(_field) memsink->mem->_field = frame->_field
# define COPY(_field) sink->mem->_field = frame->_field
COPY(used);
COPY(width);
COPY(height);
@ -157,49 +157,49 @@ int memsink_server_put(memsink_s *memsink, const frame_s *frame) {
COPY(grab_ts);
COPY(encode_begin_ts);
COPY(encode_end_ts);
memcpy(memsink->mem->data, frame->data, frame->used);
memcpy(sink->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->name);
if (sem_post(sink->sig_sem) < 0) {
LOG_PERROR("%s sink: Can't post signal semaphore", sink->name);
return -1;
}
if (flock(memsink->fd, LOCK_UN) < 0) {
LOG_PERROR("%s sink: Can't unlock memory", memsink->name);
if (flock(sink->fd, LOCK_UN) < 0) {
LOG_PERROR("%s sink: Can't unlock memory", sink->name);
return -1;
}
LOG_VERBOSE("%s sink: Exposed new frame; full exposition time = %Lf",
memsink->name, get_now_monotonic() - now);
sink->name, get_now_monotonic() - now);
} else if (errno == EWOULDBLOCK) {
LOG_PERF("%s sink: ===== Shared memory is busy now; frame skipped", memsink->name);
LOG_PERF("%s sink: ===== Shared memory is busy now; frame skipped", sink->name);
} else {
LOG_PERROR("%s sink: Can't lock memory", memsink->name);
LOG_PERROR("%s sink: Can't lock memory", sink->name);
return -1;
}
return 0;
}
int memsink_client_get(memsink_s *memsink, frame_s *frame) { // cppcheck-suppress unusedFunction
assert(!memsink->server); // Client only
int memsink_client_get(memsink_s *sink, frame_s *frame) { // cppcheck-suppress unusedFunction
assert(!sink->server); // Client only
if (_sem_timedwait_monotonic(memsink->sig_sem, memsink->timeout) < 0) {
if (_sem_timedwait_monotonic(sink->sig_sem, sink->timeout) < 0) {
if (errno == EAGAIN) {
return -2;
}
LOG_PERROR("%s src: Can't wait signal semaphore", memsink->name);
LOG_PERROR("%s sink: Can't wait signal semaphore", sink->name);
return -1;
}
if (_flock_timedwait_monotonic(memsink->fd, memsink->timeout) < 0) {
if (_flock_timedwait_monotonic(sink->fd, sink->timeout) < 0) {
if (errno == EWOULDBLOCK) {
return -2;
}
LOG_PERROR("%s src: Can't lock memory", memsink->name);
LOG_PERROR("%s sink: Can't lock memory", sink->name);
return -1;
}
# define COPY(_field) frame->_field = memsink->mem->_field
# define COPY(_field) frame->_field = sink->mem->_field
COPY(width);
COPY(height);
COPY(format);
@ -207,11 +207,11 @@ int memsink_client_get(memsink_s *memsink, frame_s *frame) { // cppcheck-suppres
COPY(grab_ts);
COPY(encode_begin_ts);
COPY(encode_end_ts);
frame_set_data(frame, memsink->mem->data, memsink->mem->used);
frame_set_data(frame, sink->mem->data, sink->mem->used);
# undef COPY
if (flock(memsink->fd, LOCK_UN) < 0) {
LOG_PERROR("%s src: Can't unlock memory", memsink->name);
if (flock(sink->fd, LOCK_UN) < 0) {
LOG_PERROR("%s sink: Can't unlock memory", sink->name);
return -1;
}
return 0;

View File

@ -74,7 +74,7 @@ typedef struct {
memsink_s *memsink_init(const char *name, const char *prefix, bool server, mode_t mode, bool rm, unsigned timeout);
void memsink_destroy(memsink_s *memsink);
void memsink_destroy(memsink_s *sink);
int memsink_server_put(memsink_s *memsink, const frame_s *frame);
int memsink_client_get(memsink_s *memsink, frame_s *frame);
int memsink_server_put(memsink_s *sink, const frame_s *frame);
int memsink_client_get(memsink_s *sink, frame_s *frame);

View File

@ -1,35 +1,26 @@
#include <stdio.h>
#include <assert.h>
#include <bcm_host.h>
#include "../libs/common/logging.h"
#include "../libs/common/frame.h"
#include "../libs/memsink/memsink.h"
#include "../libs/h264/encoder.h"
int main(void) {
LOGGING_INIT;
log_level = 3;
bcm_host_init();
frame_s *src = frame_init("src");
frame_s *dest = frame_init("dest");
h264_encoder_s *encoder = h264_encoder_init();
memsink_s *memsink = memsink_init("RAW", "test", false, 0, 0, (long double)encoder->fps / (long double)encoder->gop);
assert(memsink);
frame_s *frame = frame_init("h264");
memsink_s *sink = memsink_init("h264", "test", false, 0, 0, 0.1);
assert(sink);
FILE *fp = fopen("test.h264", "wb");
assert(fp);
int error = 0;
while ((error = memsink_client_get(memsink, src)) != -1) {
if (error == 0 /*|| (error == -2 && src->used > 0)*/) {
if (!h264_encoder_compress(encoder, src, dest)) {
LOG_INFO("frame %Lf", get_now_monotonic() - dest->grab_ts);
fwrite(dest->data, 1, dest->used, fp);
fflush(fp);
}
while ((error = memsink_client_get(sink, frame)) != -1) {
if (error == 0 /*|| (error == -2 && frame->used > 0)*/) {
LOG_INFO("frame %Lf", get_now_monotonic() - frame->grab_ts);
fwrite(frame->data, 1, frame->used, fp);
fflush(fp);
}
}
fclose(fp);

View File

@ -48,10 +48,6 @@
#include "xioctl.h"
#ifdef WITH_MEMSINK
# include "../libs/memsink/memsink.h"
#endif
#define VIDEO_MIN_WIDTH ((unsigned)160)
#define VIDEO_MAX_WIDTH ((unsigned)10240)

View File

@ -32,9 +32,7 @@ static const struct {
# ifdef WITH_OMX
{"OMX", ENCODER_TYPE_OMX},
# endif
# ifdef WITH_MEMSINK
{"NOOP", ENCODER_TYPE_NOOP},
# endif
};
@ -151,12 +149,10 @@ void encoder_prepare(encoder_s *encoder, device_s *dev) {
}
}
# endif
# ifdef WITH_MEMSINK
else if (type == ENCODER_TYPE_NOOP) {
ER(n_workers) = 1;
quality = 0;
}
# endif
goto ok;
@ -172,12 +168,9 @@ void encoder_prepare(encoder_s *encoder, device_s *dev) {
quality = dev->jpeg_quality;
ok:
# ifdef WITH_MEMSINK
if (type == ENCODER_TYPE_NOOP) {
LOG_INFO("Using JPEG NOOP encoder");
} else
# endif
if (quality == 0) {
} else if (quality == 0) {
LOG_INFO("Using JPEG quality: encoder default");
} else {
LOG_INFO("Using JPEG quality: %u%%", quality);
@ -227,12 +220,10 @@ int encoder_compress(encoder_s *encoder, unsigned worker_number, frame_s *src, f
}
}
# endif
# ifdef WITH_MEMSINK
else if (ER(type) == ENCODER_TYPE_NOOP) {
LOG_VERBOSE("Compressing buffer using NOOP (do nothing)");
usleep(5000); // Просто чтобы работала логика desired_fps
}
# endif
dest->encode_end_ts = get_now_monotonic();
return 0;

View File

@ -51,17 +51,11 @@
# define ENCODER_TYPES_OMX_HINT ""
#endif
#ifdef WITH_MEMSINK
# define ENCODER_TYPES_NOOP_HINT ", NOOP"
#else
# define ENCODER_TYPES_NOOP_HINT ""
#endif
#define ENCODER_TYPES_STR \
"CPU, HW" \
ENCODER_TYPES_OMX_HINT \
ENCODER_TYPES_NOOP_HINT
", NOOP"
typedef enum {
ENCODER_TYPE_UNKNOWN, // Only for encoder_parse_type() and main()
@ -70,9 +64,7 @@ typedef enum {
# ifdef WITH_OMX
ENCODER_TYPE_OMX,
# endif
# ifdef WITH_MEMSINK
ENCODER_TYPE_NOOP,
# endif
} encoder_type_e;
typedef struct {

View File

@ -59,11 +59,11 @@ omx_encoder_s *omx_encoder_init(void) {
// - https://bitbucket.org/bensch128/omxjpegencode/src/master/jpeg_encoder.cpp
// - http://home.nouwen.name/RaspberryPi/documentation/ilcomponents/image_encode.html
LOG_INFO("Initializing OMX encoder ...");
omx_encoder_s *omx;
A_CALLOC(omx, 1);
LOG_INFO("Initializing OMX encoder ...");
if (vcos_semaphore_create(&omx->handler_sem, "handler_sem", 0) != VCOS_SUCCESS) {
LOG_ERROR("Can't create VCOS semaphore");
goto error;
@ -278,11 +278,11 @@ static int _omx_init_disable_ports(omx_encoder_s *omx) {
}
static int _omx_setup_input(omx_encoder_s *omx, device_s *dev) {
LOG_DEBUG("Setting up OMX JPEG input port ...");
OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
LOG_DEBUG("Setting up OMX JPEG input port ...");
if (omx_component_get_portdef(&omx->encoder, &portdef, _INPUT_PORT) < 0) {
LOG_ERROR("... first");
return -1;
@ -333,11 +333,11 @@ static int _omx_setup_input(omx_encoder_s *omx, device_s *dev) {
}
static int _omx_setup_output(omx_encoder_s *omx, unsigned quality) {
LOG_DEBUG("Setting up OMX JPEG output port ...");
OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
LOG_DEBUG("Setting up OMX JPEG output port ...");
if (omx_component_get_portdef(&omx->encoder, &portdef, _OUTPUT_PORT) < 0) {
LOG_ERROR("... first");
return -1;

View File

@ -40,27 +40,29 @@ static const char *_mmal_error_to_string(MMAL_STATUS_T error);
h264_encoder_s *h264_encoder_init(void) {
LOG_INFO("H264: Initializing MMAL encoder ...");
h264_encoder_runtime_s *run;
A_CALLOC(run, 1);
run->unjpegged = frame_init("h264_unjpegged_src");
run->tmp = frame_init("h264_tmp");
run->last_online = -1;
h264_encoder_s *encoder;
A_CALLOC(encoder, 1);
encoder->gop = 60;
encoder->gop = 45; // 60
encoder->bps = 5000 * 1000; // Kbps * 1000
encoder->fps = 30;
encoder->fps = 0; // FIXME: 30 or 0? https://github.com/6by9/yavta/blob/master/yavta.c#L210
encoder->run = run;
if (vcos_semaphore_create(&run->handler_sem, "h264_handler_sem", 0) != VCOS_SUCCESS) {
LOG_PERROR("Can't create VCOS semaphore");
LOG_PERROR("H264: Can't create VCOS semaphore");
goto error;
}
run->i_handler_sem = true;
MMAL_STATUS_T error = mmal_wrapper_create(&run->wrapper, MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER);
if (error != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't create MMAL wrapper");
LOG_ERROR_MMAL(error, "H264: Can't create MMAL wrapper");
run->wrapper = NULL;
goto error;
}
@ -75,12 +77,14 @@ h264_encoder_s *h264_encoder_init(void) {
}
void h264_encoder_destroy(h264_encoder_s *encoder) {
LOG_INFO("H264: Destroying MMAL encoder ...");
_h264_encoder_cleanup(encoder);
if (RUN(wrapper)) {
MMAL_STATUS_T error = mmal_wrapper_destroy(RUN(wrapper));
if (error != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't destroy MMAL encoder");
LOG_ERROR_MMAL(error, "H264: Can't destroy MMAL encoder");
}
}
@ -88,7 +92,7 @@ void h264_encoder_destroy(h264_encoder_s *encoder) {
vcos_semaphore_delete(&RUN(handler_sem));
}
frame_destroy(RUN(unjpegged));
frame_destroy(RUN(tmp));
free(encoder->run);
free(encoder);
}
@ -99,13 +103,22 @@ int h264_encoder_compress(h264_encoder_s *encoder, const frame_s *src, frame_s *
assert(src->height > 0);
assert(src->format > 0);
frame_copy_meta(src, dest);
dest->encode_begin_ts = get_now_monotonic();
dest->format = V4L2_PIX_FMT_H264;
if (src->format == V4L2_PIX_FMT_MJPEG || src->format == V4L2_PIX_FMT_JPEG) {
LOG_DEBUG("Input frame format is JPEG; decoding ...");
if (unjpeg(src, RUN(unjpegged), true) < 0) {
LOG_DEBUG("H264: Input frame format is JPEG; decoding ...");
if (unjpeg(src, RUN(tmp), true) < 0) {
return -1;
}
src = RUN(unjpegged);
LOG_VERBOSE("H264: JPEG decoded; time=%Lf", get_now_monotonic() - dest->encode_begin_ts);
} else {
LOG_DEBUG("H264: Copying source to tmp buffer ...");
frame_copy(src, RUN(tmp));
LOG_VERBOSE("H264: Source copied; time=%Lf", get_now_monotonic() - dest->encode_begin_ts);
}
src = RUN(tmp);
if (RUN(i_width) != src->width || RUN(i_height) != src->height || RUN(i_format) != src->format) {
if (_h264_encoder_configure(encoder, src) < 0) {
@ -114,23 +127,31 @@ int h264_encoder_compress(h264_encoder_s *encoder, const frame_s *src, frame_s *
RUN(last_online) = -1;
}
if (_h264_encoder_compress_raw(encoder, src, dest, (RUN(last_online) != src->online)) < 0) {
bool force_key = (RUN(last_online) != src->online);
if (_h264_encoder_compress_raw(encoder, src, dest, force_key) < 0) {
_h264_encoder_cleanup(encoder);
return -1;
}
dest->encode_end_ts = get_now_monotonic();
LOG_VERBOSE("H264: Compressed new frame: size=%zu, time=%0.3Lf, force_key=%d",
dest->used, dest->encode_end_ts - dest->encode_begin_ts, force_key);
RUN(last_online) = src->online;
return 0;
}
static int _h264_encoder_configure(h264_encoder_s *encoder, const frame_s *frame) {
LOG_INFO("H264: Reconfiguring MMAL encoder ...");
MMAL_STATUS_T error;
# define PREPARE_PORT(_id) { \
RUN(_id##_port) = RUN(wrapper->_id[0]); \
if (RUN(_id##_port->is_enabled)) { \
if ((error = mmal_wrapper_port_disable(RUN(_id##_port))) != MMAL_SUCCESS) { \
LOG_ERROR_MMAL(error, "Can't disable MMAL %s port while configuring", #_id); \
LOG_ERROR_MMAL(error, "H264: Can't disable MMAL %s port while configuring", #_id); \
goto error; \
} \
} \
@ -138,21 +159,21 @@ static int _h264_encoder_configure(h264_encoder_s *encoder, const frame_s *frame
# define COMMIT_PORT(_id) { \
if ((error = mmal_port_format_commit(RUN(_id##_port))) != MMAL_SUCCESS) { \
LOG_ERROR_MMAL(error, "Can't commit MMAL %s port", #_id); \
LOG_ERROR_MMAL(error, "H264: Can't commit MMAL %s port", #_id); \
goto error; \
} \
}
# define SET_PORT_PARAM(_id, _type, _key, _value) { \
if ((error = mmal_port_parameter_set_##_type(RUN(_id##_port), MMAL_PARAMETER_##_key, _value)) != MMAL_SUCCESS) { \
LOG_ERROR_MMAL(error, "Can't set %s for the %s port", #_key, #_id); \
LOG_ERROR_MMAL(error, "H264: Can't set %s for the %s port", #_key, #_id); \
goto error; \
} \
}
# define ENABLE_PORT(_id) { \
if ((error = mmal_wrapper_port_enable(RUN(_id##_port), MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE)) != MMAL_SUCCESS) { \
LOG_ERROR_MMAL(error, "Can't enable MMAL %s port", #_id); \
LOG_ERROR_MMAL(error, "H264: Can't enable MMAL %s port", #_id); \
goto error; \
} \
}
@ -211,7 +232,7 @@ static int _h264_encoder_configure(h264_encoder_s *encoder, const frame_s *frame
profile.profile[0].profile = MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
profile.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // Supports 1080p
if ((error = mmal_port_parameter_set(RUN(output_port), &profile.hdr)) != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't set MMAL_PARAMETER_PROFILE for the output port");
LOG_ERROR_MMAL(error, "H264: Can't set MMAL_PARAMETER_PROFILE for the output port");
goto error;
}
}
@ -256,7 +277,7 @@ static void _h264_encoder_cleanup(h264_encoder_s *encoder) {
# define DISABLE_PORT(_id) { \
if (RUN(_id##_port)) { \
if ((error = mmal_wrapper_port_disable(RUN(_id##_port))) != MMAL_SUCCESS) { \
LOG_ERROR_MMAL(error, "Can't disable MMAL %s port", #_id); \
LOG_ERROR_MMAL(error, "H264: Can't disable MMAL %s port", #_id); \
} \
RUN(_id##_port) = NULL; \
} \
@ -278,22 +299,17 @@ static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *sr
assert(src->height == RUN(i_height));
assert(src->format == RUN(i_format));
LOG_DEBUG("H264: Compressing new frame; force_key=%d ...", force_key);
MMAL_STATUS_T error;
LOG_DEBUG("Compressing new H264 frame; force_key=%d ...", force_key);
frame_copy_meta(src, dest);
dest->format = V4L2_PIX_FMT_H264;
dest->encode_begin_ts = get_now_monotonic();
dest->used = 0;
if (force_key) {
if ((error = mmal_port_parameter_set_boolean(
RUN(output_port),
MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
MMAL_TRUE
)) != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't request keyframe");
LOG_ERROR_MMAL(error, "H264: Can't request keyframe");
return -1;
}
}
@ -303,11 +319,13 @@ static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *sr
bool eos = false;
bool sent = false;
dest->used = 0;
while (!eos) {
out = NULL;
while (mmal_wrapper_buffer_get_empty(RUN(output_port), &out, 0) == MMAL_SUCCESS) {
if ((error = mmal_port_send_buffer(RUN(output_port), out)) != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't send MMAL output buffer");
LOG_ERROR_MMAL(error, "H264: Can't send MMAL output buffer");
return -1;
}
}
@ -319,7 +337,7 @@ static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *sr
in->offset = 0;
in->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
if ((error = mmal_port_send_buffer(RUN(input_port), in)) != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't send MMAL input buffer");
LOG_ERROR_MMAL(error, "H264: Can't send MMAL input buffer");
return -1;
}
sent = true;
@ -330,7 +348,7 @@ static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *sr
vcos_semaphore_wait(&RUN(handler_sem));
continue;
} else if (error != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't get MMAL output buffer");
LOG_ERROR_MMAL(error, "H264: Can't get MMAL output buffer");
return -1;
}
@ -341,12 +359,8 @@ static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *sr
}
if ((error = mmal_port_flush(RUN(output_port))) != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't flush MMAL output buffer; ignored");
LOG_ERROR_MMAL(error, "H264: Can't flush MMAL output buffer; ignored");
}
dest->encode_end_ts = get_now_monotonic();
LOG_VERBOSE("Compressed new H264 frame: size=%zu, time=%0.3Lf, force_key=%d",
dest->used, dest->encode_end_ts - dest->encode_begin_ts, force_key);
return 0;
}

View File

@ -34,10 +34,10 @@
#include <interface/mmal/util/mmal_component_wrapper.h>
#include <interface/mmal/util/mmal_util_params.h>
#include "../common/tools.h"
#include "../common/logging.h"
#include "../common/frame.h"
#include "../common/unjpeg.h"
#include "../../libs/common/tools.h"
#include "../../libs/common/logging.h"
#include "../../libs/common/frame.h"
#include "../../libs/common/unjpeg.h"
typedef struct {
@ -47,7 +47,7 @@ typedef struct {
VCOS_SEMAPHORE_T handler_sem;
bool i_handler_sem;
frame_s *unjpegged;
frame_s *tmp;
int last_online;
unsigned i_width;

View File

@ -82,11 +82,11 @@ enum _OPT_VALUES {
_O_TCP_NODELAY,
_O_SERVER_TIMEOUT,
#ifdef WITH_MEMSINK
_O_RAW_SINK,
_O_RAW_SINK_MODE,
_O_RAW_SINK_RM,
_O_RAW_SINK_TIMEOUT,
#ifdef WITH_OMX
_O_H264_SINK,
_O_H264_SINK_MODE,
_O_H264_SINK_RM,
_O_H264_SINK_TIMEOUT,
#endif
#ifdef WITH_GPIO
@ -167,11 +167,11 @@ static const struct option _LONG_OPTS[] = {
{"tcp-nodelay", no_argument, NULL, _O_TCP_NODELAY},
{"server-timeout", required_argument, NULL, _O_SERVER_TIMEOUT},
#ifdef WITH_MEMSINK
{"raw-sink", required_argument, NULL, _O_RAW_SINK},
{"raw-sink-mode", required_argument, NULL, _O_RAW_SINK_MODE},
{"raw-sink-rm", no_argument, NULL, _O_RAW_SINK_RM},
{"raw-sink-timeout", required_argument, NULL, _O_RAW_SINK_TIMEOUT},
#ifdef WITH_OMX
{"h264-sink", required_argument, NULL, _O_H264_SINK},
{"h264-sink-mode", required_argument, NULL, _O_H264_SINK_MODE},
{"h264-sink-rm", no_argument, NULL, _O_H264_SINK_RM},
{"h264-sink-timeout", required_argument, NULL, _O_H264_SINK_TIMEOUT},
#endif
#ifdef WITH_GPIO
@ -228,9 +228,9 @@ options_s *options_init(unsigned argc, char *argv[]) {
}
void options_destroy(options_s *options) {
# ifdef WITH_MEMSINK
if (options->raw_sink) {
memsink_destroy(options->raw_sink);
# ifdef WITH_OMX
if (options->h264_sink) {
memsink_destroy(options->h264_sink);
}
# endif
if (options->blank) {
@ -313,11 +313,11 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
char *blank_path = NULL;
# ifdef WITH_MEMSINK
char *raw_sink_name = NULL;
mode_t raw_sink_mode = 0660;
bool raw_sink_rm = false;
unsigned raw_sink_timeout = 1;
# ifdef WITH_OMX
char *h264_sink_name = NULL;
mode_t h264_sink_mode = 0660;
bool h264_sink_rm = false;
unsigned h264_sink_timeout = 1;
# endif
# ifdef WITH_SETPROCTITLE
@ -410,11 +410,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_SERVER_TIMEOUT: OPT_NUMBER("--server-timeout", server->timeout, 1, 60, 0);
# ifdef WITH_MEMSINK
case _O_RAW_SINK: OPT_SET(raw_sink_name, optarg);
case _O_RAW_SINK_MODE: OPT_NUMBER("--raw-sink-mode", raw_sink_mode, INT_MIN, INT_MAX, 8);
case _O_RAW_SINK_RM: OPT_SET(raw_sink_rm, true);
case _O_RAW_SINK_TIMEOUT: OPT_NUMBER("--raw-sink-timeout", raw_sink_timeout, 1, 60, 0);
# ifdef WITH_OMX
case _O_H264_SINK: OPT_SET(h264_sink_name, optarg);
case _O_H264_SINK_MODE: OPT_NUMBER("--h264-sink-mode", h264_sink_mode, INT_MIN, INT_MAX, 8);
case _O_H264_SINK_RM: OPT_SET(h264_sink_rm, true);
case _O_H264_SINK_TIMEOUT: OPT_NUMBER("--h264-sink-timeout", h264_sink_timeout, 1, 60, 0);
# endif
# ifdef WITH_GPIO
@ -456,18 +456,18 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
options->blank = blank_frame_init(blank_path);
stream->blank = options->blank;
# ifdef WITH_MEMSINK
if (raw_sink_name && raw_sink_name[0] != '\0') {
options->raw_sink = memsink_init(
"RAW",
raw_sink_name,
# ifdef WITH_OMX
if (h264_sink_name && h264_sink_name[0] != '\0') {
options->h264_sink = memsink_init(
"h264",
h264_sink_name,
true,
raw_sink_mode,
raw_sink_rm,
raw_sink_timeout
h264_sink_mode,
h264_sink_rm,
h264_sink_timeout
);
}
stream->raw_sink = options->raw_sink;
stream->h264_sink = options->h264_sink;
# endif
# ifdef WITH_SETPROCTITLE
@ -561,12 +561,6 @@ static void _features(void) {
puts("- WITH_OMX");
# endif
# ifdef WITH_MEMSINK
puts("+ WITH_MEMSINK");
# else
puts("- WITH_MEMSINK");
# endif
# ifdef WITH_GPIO
puts("+ WITH_GPIO");
# else
@ -633,9 +627,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");
# endif
printf(" * HW ─── Use pre-encoded MJPG frames directly from camera hardware.\n");
# ifdef WITH_MEMSINK
printf(" * NOOP ─ Don't compress stream. Useful for the RAW sink.\n\n");
# endif
printf(" * NOOP ─ Don't compress MJPG stream (do nothing).\n\n");
# ifdef WITH_OMX
printf(" -g|--glitched-resolutions <WxH,...> ─ Comma-separated list of resolutions that require forced\n");
printf(" encoding on CPU instead of OMX. Default: disabled.\n\n");
@ -687,14 +679,14 @@ static void _help(device_s *dev, encoder_s *encoder, stream_s *stream, server_s
printf(" 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);
#ifdef WITH_MEMSINK
printf("RAW sink options:\n");
#ifdef WITH_OMX
printf("H264 sink options:\n");
printf("═════════════════\n");
printf(" --raw-sink <name> ──────── Use the shared memory to sink RAW frames before encoding.\n");
printf(" Most likely you will never need it. Default: disabled.\n\n");
printf(" --raw-sink-mode <mode> ─── Set RAW sink permissions (like 777). Default: 660.\n\n");
printf(" --raw-sink-rm ──────────── Remove shared memory on stop. Default: disabled.\n\n");
printf(" --raw-sink-timeout <sec> ─ Timeout for lock. Default: 1.\n\n");
printf(" --h264-sink <name> ──────── Use the shared memory to sink H264 frames encoded by MMAL.\n");
printf(" Most likely you will never need it. Default: disabled.\n\n");
printf(" --h264-sink-mode <mode> ─── Set H264 sink permissions (like 777). Default: 660.\n\n");
printf(" --h264-sink-rm ──────────── Remove shared memory on stop. Default: disabled.\n\n");
printf(" --h264-sink-timeout <sec> ─ Timeout for lock. Default: 1.\n\n");
#endif
#ifdef WITH_GPIO
printf("GPIO options:\n");

View File

@ -37,7 +37,7 @@
#include "../libs/common/logging.h"
#include "../libs/common/process.h"
#include "../libs/common/frame.h"
#ifdef WITH_MEMSINK
#ifdef WITH_OMX
# include "../libs/memsink/memsink.h"
#endif
@ -56,8 +56,8 @@ typedef struct {
char **argv;
char **argv_copy;
frame_s *blank;
# ifdef WITH_MEMSINK
memsink_s *raw_sink;
# ifdef WITH_OMX
memsink_s *h264_sink;
# endif
} options_s;

View File

@ -24,7 +24,6 @@
typedef struct {
device_s *dev;
encoder_s *encoder;
hw_buffer_s *hw;
char *dest_role;
@ -36,10 +35,16 @@ static workers_pool_s *_stream_init_loop(stream_s *stream);
static workers_pool_s *_stream_init_one(stream_s *stream);
static bool _stream_expose_frame(stream_s *stream, frame_s *frame, unsigned captured_fps);
static void *_worker_job_init(worker_s *wr, void *arg);
static void *_worker_job_init(worker_s *wr, void *v_arg);
static void _worker_job_destroy(void *v_job);
static bool _worker_run_job(worker_s *wr);
#ifdef WITH_OMX
static h264_stream_s *_h264_stream_init(memsink_s *sink);
static void _h264_stream_destroy(h264_stream_s *h264);
static void _h264_stream_process(h264_stream_s *h264, const frame_s *frame);
#endif
stream_s *stream_init(device_s *dev, encoder_s *encoder) {
process_s *proc;
@ -76,6 +81,12 @@ void stream_loop(stream_s *stream) {
LOG_INFO("Using V4L2 device: %s", stream->dev->path);
LOG_INFO("Using desired FPS: %u", stream->dev->desired_fps);
# ifdef WITH_OMX
if (stream->h264_sink) {
stream->h264 = _h264_stream_init(stream->h264_sink);
}
# endif
for (workers_pool_s *pool; (pool = _stream_init_loop(stream)) != NULL;) {
long double grab_after = 0;
unsigned fluency_passed = 0;
@ -90,16 +101,24 @@ void stream_loop(stream_s *stream) {
LOG_DEBUG("Waiting for worker ...");
worker_s *ready_wr = workers_pool_wait(pool);
_job_s *ready_job = (_job_s *)(ready_wr->job);
if (!ready_wr->job_failed) {
if (ready_wr->job_timely) {
_stream_expose_frame(stream, ((_job_s *)(ready_wr->job))->dest, captured_fps);
LOG_PERF("##### Encoded frame exposed; worker=%s", ready_wr->name);
} else {
LOG_PERF("----- Encoded frame dropped; worker=%s", ready_wr->name);
if (ready_job->hw) {
if (device_release_buffer(stream->dev, ready_job->hw) < 0) {
ready_wr->job_failed = true;
}
ready_job->hw = NULL;
if (!ready_wr->job_failed) {
if (ready_wr->job_timely) {
_stream_expose_frame(stream, ready_job->dest, captured_fps);
LOG_PERF("##### Encoded frame exposed; worker=%s", ready_wr->name);
} else {
LOG_PERF("----- Encoded frame dropped; worker=%s", ready_wr->name);
}
} else {
break;
}
} else {
break;
}
if (atomic_load(&stream->proc->stop)) {
@ -161,18 +180,15 @@ void stream_loop(stream_s *stream) {
grab_after = now + fluency_delay;
LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after);
# ifdef WITH_MEMSINK
if (stream->raw_sink) {
if (memsink_server_put(stream->raw_sink, &hw->raw) < 0) {
stream->raw_sink = NULL;
LOG_ERROR("RAW sink completely disabled due error");
}
}
# endif
((_job_s *)ready_wr->job)->hw = hw;
ready_job->hw = hw;
workers_pool_assign(pool, ready_wr);
LOG_DEBUG("Assigned new frame in buffer %d to worker %s", buf_index, ready_wr->name);
# ifdef WITH_OMX
if (stream->h264) {
_h264_stream_process(stream->h264, &hw->raw);
}
# endif
}
} else if (buf_index != -2) { // -2 for broken frame
break;
@ -201,6 +217,12 @@ void stream_loop(stream_s *stream) {
gpio_set_stream_online(false);
# endif
}
# ifdef WITH_OMX
if (stream->h264) {
_h264_stream_destroy(stream->h264);
}
# endif
}
void stream_loop_break(stream_s *stream) {
@ -212,6 +234,7 @@ void stream_switch_slowdown(stream_s *stream, bool slowdown) {
}
static workers_pool_s *_stream_init_loop(stream_s *stream) {
workers_pool_s *pool = NULL;
int access_error = 0;
@ -219,12 +242,9 @@ static workers_pool_s *_stream_init_loop(stream_s *stream) {
while (!atomic_load(&stream->proc->stop)) {
if (_stream_expose_frame(stream, NULL, 0)) {
# ifdef WITH_MEMSINK
if (stream->raw_sink) {
if (memsink_server_put(stream->raw_sink, stream->blank) < 0) {
stream->raw_sink = NULL;
LOG_ERROR("RAW sink completely disabled due error");
}
# ifdef WITH_OMX
if (stream->h264) {
_h264_stream_process(stream->h264, stream->blank);
}
# endif
}
@ -340,12 +360,11 @@ static bool _stream_expose_frame(stream_s *stream, frame_s *frame, unsigned capt
# undef VID
}
static void *_worker_job_init(worker_s *wr, void *arg) {
static void *_worker_job_init(worker_s *wr, void *v_stream) {
stream_s *stream = (stream_s *)v_stream;
_job_s *job;
A_CALLOC(job, 1);
stream_s *stream = (stream_s *)arg;
job->dev = stream->dev;
job->encoder = stream->encoder;
const size_t dest_role_len = strlen(wr->name) + 16;
@ -367,19 +386,50 @@ static bool _worker_run_job(worker_s *wr) {
LOG_DEBUG("Worker %s compressing JPEG from buffer %u ...", wr->name, job->hw->buf_info.index);
bool ok = !encoder_compress(job->encoder, wr->number, &job->hw->raw, job->dest);
if (device_release_buffer(job->dev, job->hw) == 0) {
if (ok) {
LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%s, buffer=%u",
job->dest->used,
job->dest->encode_end_ts - job->dest->encode_begin_ts,
wr->name,
job->hw->buf_info.index);
} else {
LOG_VERBOSE("Compression failed: worker=%s, buffer=%u", wr->name, job->hw->buf_info.index);
}
if (ok) {
LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%s, buffer=%u",
job->dest->used,
job->dest->encode_end_ts - job->dest->encode_begin_ts,
wr->name,
job->hw->buf_info.index);
} else {
ok = false;
LOG_VERBOSE("Compression failed: worker=%s, buffer=%u", wr->name, job->hw->buf_info.index);
}
return ok;
}
#ifdef WITH_OMX
static h264_stream_s *_h264_stream_init(memsink_s *sink) {
h264_stream_s *h264;
A_CALLOC(h264, 1);
if ((h264->encoder = h264_encoder_init()) == NULL) {
goto error;
}
h264->dest = frame_init("h264_dest");
h264->sink = sink;
return h264;
error:
_h264_stream_destroy(h264);
return NULL;
}
static void _h264_stream_destroy(h264_stream_s *h264) {
if (h264->encoder) {
h264_encoder_destroy(h264->encoder);
}
if (h264->dest) {
frame_destroy(h264->dest);
}
free(h264);
}
static void _h264_stream_process(h264_stream_s *h264, const frame_s *frame) {
if (h264_encoder_compress(h264->encoder, frame, h264->dest) == 0) {
memsink_server_put(h264->sink, h264->dest);
}
}
#endif

View File

@ -41,7 +41,8 @@
#include "device.h"
#include "encoder.h"
#include "workers.h"
#ifdef WITH_MEMSINK
#ifdef WITH_OMX
# include "h264/encoder.h"
# include "../libs/memsink/memsink.h"
#endif
#ifdef WITH_GPIO
@ -62,6 +63,14 @@ typedef struct {
pthread_mutex_t mutex;
} video_s;
#ifdef WITH_OMX
typedef struct {
h264_encoder_s *encoder;
frame_s *dest;
memsink_s *sink;
} h264_stream_s;
#endif
typedef struct {
int last_as_blank;
unsigned error_delay;
@ -69,12 +78,15 @@ typedef struct {
device_s *dev;
encoder_s *encoder;
frame_s *blank;
# ifdef WITH_MEMSINK
memsink_s *raw_sink;
# ifdef WITH_OMX
memsink_s *h264_sink;
# endif
process_s *proc;
video_s *video;
process_s *proc;
video_s *video;
# ifdef WITH_OMX
h264_stream_s *h264;
# endif
} stream_s;

View File

@ -32,7 +32,7 @@ workers_pool_s *workers_pool_init(
void (*job_destroy)(void *),
bool (*run_job)(worker_s *)) {
LOG_INFO("Creating pool %s with %u workers ...", name, n_workers);
LOG_INFO("Creating pool '%s' with %u workers ...", name, n_workers);
workers_pool_s *pool;
A_CALLOC(pool, 1);
@ -74,7 +74,7 @@ workers_pool_s *workers_pool_init(
}
void workers_pool_destroy(workers_pool_s *pool) {
LOG_INFO("Destroying pool %s ...", pool->name);
LOG_INFO("Destroying workers pool '%s' ...", pool->name);
atomic_store(&pool->stop, true);
for (unsigned number = 0; number < pool->n_workers; ++number) {

View File

@ -94,7 +94,7 @@ OMX ─ GPU hardware accelerated MJPG encoding with OpenMax (required \fBWITH_OM
HW ─ Use pre-encoded MJPG frames directly from camera hardware.
NOOP ─ Don't compress stream. Useful for the RAW sink.
NOOP ─ Don't compress MJPG stream (do nothing).
.TP
.BR \-g\ \fIWxH,... ", " \-\-glitched\-resolutions\ \fIWxH,...
Comma-separated list of resolutions that require forced
@ -196,20 +196,20 @@ Set Access\-Control\-Allow\-Origin header. Default: disabled.
.BR \-\-server\-timeout\ \fIsec
Timeout for client connections. Default: 10.
.SS "RAW sink options"
Available only if \fBWITH_MEMSINK\fR feature enabled.
.SS "H264 sink options"
Available only if \fBWITH_OMX\fR feature enabled.
.TP
.BR \-\-raw\-sink\ \fIname
Use the specified shared memory object to sink RAW frames before encoding.
.BR \-\-h264\-sink\ \fIname
Use the specified shared memory object to sink H264 frames encoded by MMAL.
Most likely you will never need it. Default: disabled.
.TP
.BR \-\-raw\-sink\-mode\ \fImode
Set RAW sink permissions (like 777). Default: 660.
.BR \-\-h264\-sink\-mode\ \fImode
Set H264 sink permissions (like 777). Default: 660.
.TP
.BR \-\-raw\-sink\-rm
.BR \-\-h264\-sink\-rm
Remove shared memory on stop. Default: disabled.
.TP
.BR \-\-raw\-sink\-timeout\ \fIsec
.BR \-\-h264\-sink\-timeout\ \fIsec
Timeout for lock. Default: 1.
.SS "Process options"