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

@@ -1,384 +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 "encoder.h"
static int _h264_encoder_configure(h264_encoder_s *encoder, const frame_s *frame);
static void _h264_encoder_cleanup(h264_encoder_s *encoder);
static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *src, frame_s *dest, bool force_key);
static void _mmal_callback(MMAL_WRAPPER_T *wrapper);
static const char *_mmal_error_to_string(MMAL_STATUS_T error);
#define RUN(_next) encoder->run->_next
#define LOG_ERROR_MMAL(_error, _msg, ...) { \
LOG_ERROR(_msg ": %s", ##__VA_ARGS__, _mmal_error_to_string(_error)); \
}
h264_encoder_s *h264_encoder_init(void) {
h264_encoder_runtime_s *run;
A_CALLOC(run, 1);
run->unjpegged = frame_init("h264_unjpegged_src");
run->last_online = -1;
h264_encoder_s *encoder;
A_CALLOC(encoder, 1);
encoder->gop = 60;
encoder->bps = 5000 * 1000; // Kbps * 1000
encoder->fps = 30;
encoder->run = run;
if (vcos_semaphore_create(&run->handler_sem, "h264_handler_sem", 0) != VCOS_SUCCESS) {
LOG_PERROR("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");
run->wrapper = NULL;
goto error;
}
run->wrapper->user_data = (void *)encoder;
run->wrapper->callback = _mmal_callback;
return encoder;
error:
h264_encoder_destroy(encoder);
return NULL;
}
void h264_encoder_destroy(h264_encoder_s *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");
}
}
if (RUN(i_handler_sem)) {
vcos_semaphore_delete(&RUN(handler_sem));
}
frame_destroy(RUN(unjpegged));
free(encoder->run);
free(encoder);
}
int h264_encoder_compress(h264_encoder_s *encoder, const frame_s *src, frame_s *dest) {
assert(src->used > 0);
assert(src->width > 0);
assert(src->height > 0);
assert(src->format > 0);
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) {
return -1;
}
src = RUN(unjpegged);
}
if (RUN(i_width) != src->width || RUN(i_height) != src->height || RUN(i_format) != src->format) {
if (_h264_encoder_configure(encoder, src) < 0) {
return -1;
}
RUN(last_online) = -1;
}
if (_h264_encoder_compress_raw(encoder, src, dest, (RUN(last_online) != src->online)) < 0) {
_h264_encoder_cleanup(encoder);
return -1;
}
RUN(last_online) = src->online;
return 0;
}
static int _h264_encoder_configure(h264_encoder_s *encoder, const frame_s *frame) {
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); \
goto error; \
} \
} \
}
# 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); \
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); \
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); \
goto error; \
} \
}
_h264_encoder_cleanup(encoder);
RUN(wrapper->status) = MMAL_SUCCESS; // Это реально надо?
{
PREPARE_PORT(input);
# define IFMT(_next) RUN(input_port->format->_next)
IFMT(type) = MMAL_ES_TYPE_VIDEO;
switch (frame->format) {
case V4L2_PIX_FMT_YUYV: IFMT(encoding) = MMAL_ENCODING_YUYV; break;
case V4L2_PIX_FMT_UYVY: IFMT(encoding) = MMAL_ENCODING_UYVY; break;
case V4L2_PIX_FMT_RGB565: IFMT(encoding) = MMAL_ENCODING_RGB16; break;
case V4L2_PIX_FMT_RGB24: IFMT(encoding) = MMAL_ENCODING_RGB24; break;
default: assert(0 && "Unsupported input format for MMAL H264 encoder");
}
IFMT(es->video.width) = align_size(frame->width, 32);
IFMT(es->video.height) = align_size(frame->height, 16);
IFMT(es->video.crop.x) = 0;
IFMT(es->video.crop.y) = 0;
IFMT(es->video.crop.width) = frame->width;
IFMT(es->video.crop.height) = frame->height;
IFMT(flags) = MMAL_ES_FORMAT_FLAG_FRAMED;
RUN(input_port->buffer_size) = 1000 * 1000;
RUN(input_port->buffer_num) = RUN(input_port->buffer_num_recommended) * 4;
# undef IFMT
COMMIT_PORT(input);
SET_PORT_PARAM(input, boolean, ZERO_COPY, MMAL_FALSE);
}
{
PREPARE_PORT(output);
# define OFMT(_next) RUN(output_port->format->_next)
OFMT(type) = MMAL_ES_TYPE_VIDEO;
OFMT(encoding) = MMAL_ENCODING_H264;
OFMT(encoding_variant) = MMAL_ENCODING_VARIANT_H264_DEFAULT;
OFMT(bitrate) = encoder->bps;
OFMT(es->video.frame_rate.num) = encoder->fps;
OFMT(es->video.frame_rate.den) = 1;
RUN(output_port->buffer_size) = RUN(output_port->buffer_size_recommended) * 4;
RUN(output_port->buffer_num) = RUN(output_port->buffer_num_recommended);
# undef OFMT
COMMIT_PORT(output);
{
MMAL_PARAMETER_VIDEO_PROFILE_T profile;
MEMSET_ZERO(profile);
profile.hdr.id = MMAL_PARAMETER_PROFILE;
profile.hdr.size = sizeof(profile);
// http://blog.mediacoderhq.com/h264-profiles-and-levels
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");
goto error;
}
}
SET_PORT_PARAM(output, boolean, ZERO_COPY, MMAL_TRUE);
SET_PORT_PARAM(output, uint32, INTRAPERIOD, encoder->gop);
SET_PORT_PARAM(output, uint32, NALUNITFORMAT, MMAL_VIDEO_NALUNITFORMAT_STARTCODES);
SET_PORT_PARAM(output, boolean, MINIMISE_FRAGMENTATION, MMAL_TRUE);
SET_PORT_PARAM(output, uint32, MB_ROWS_PER_SLICE, 0);
SET_PORT_PARAM(output, boolean, VIDEO_IMMUTABLE_INPUT, MMAL_FALSE);
SET_PORT_PARAM(output, boolean, VIDEO_DROPPABLE_PFRAMES, MMAL_FALSE);
SET_PORT_PARAM(output, uint32, VIDEO_BIT_RATE, encoder->bps);
SET_PORT_PARAM(output, uint32, VIDEO_ENCODE_PEAK_RATE, encoder->bps);
SET_PORT_PARAM(output, uint32, VIDEO_ENCODE_MIN_QUANT, 16);
SET_PORT_PARAM(output, uint32, VIDEO_ENCODE_MAX_QUANT, 34);
SET_PORT_PARAM(output, uint32, VIDEO_ENCODE_FRAME_LIMIT_BITS, 1000000);
SET_PORT_PARAM(output, uint32, VIDEO_ENCODE_H264_AU_DELIMITERS, MMAL_FALSE);
}
ENABLE_PORT(input);
ENABLE_PORT(output);
RUN(i_width) = frame->width;
RUN(i_height) = frame->height;
RUN(i_format) = frame->format;
return 0;
error:
_h264_encoder_cleanup(encoder);
return -1;
# undef ENABLE_PORT
# undef SET_PORT_PARAM
# undef COMMIT_PORT
# undef PREPARE_PORT
}
static void _h264_encoder_cleanup(h264_encoder_s *encoder) {
MMAL_STATUS_T error;
# 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); \
} \
RUN(_id##_port) = NULL; \
} \
}
DISABLE_PORT(input);
DISABLE_PORT(output);
# undef DISABLE_PORT
RUN(i_width) = 0;
RUN(i_height) = 0;
RUN(i_format) = 0;
}
static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *src, frame_s *dest, bool force_key) {
assert(src->used > 0);
assert(src->width == RUN(i_width));
assert(src->height == RUN(i_height));
assert(src->format == RUN(i_format));
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");
return -1;
}
}
MMAL_BUFFER_HEADER_T *out = NULL;
MMAL_BUFFER_HEADER_T *in = NULL;
bool eos = false;
bool sent = false;
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");
return -1;
}
}
in = NULL;
if (!sent && mmal_wrapper_buffer_get_empty(RUN(input_port), &in, 0) == MMAL_SUCCESS) {
in->data = src->data;
in->length = src->used;
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");
return -1;
}
sent = true;
}
error = mmal_wrapper_buffer_get_full(RUN(output_port), &out, 0);
if (error == MMAL_EAGAIN) {
vcos_semaphore_wait(&RUN(handler_sem));
continue;
} else if (error != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "Can't get MMAL output buffer");
return -1;
}
frame_append_data(dest, out->data, out->length);
eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
mmal_buffer_header_release(out);
}
if ((error = mmal_port_flush(RUN(output_port))) != MMAL_SUCCESS) {
LOG_ERROR_MMAL(error, "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;
}
static void _mmal_callback(MMAL_WRAPPER_T *wrapper) {
vcos_semaphore_post(&((h264_encoder_s *)(wrapper->user_data))->run->handler_sem);
}
static const char *_mmal_error_to_string(MMAL_STATUS_T error) {
// http://www.jvcref.com/files/PI/documentation/html/group___mmal_types.html
# define CASE_ERROR(_name, _msg) case MMAL_##_name: return "MMAL_" #_name " [" _msg "]"
switch (error) {
case MMAL_SUCCESS: return "MMAL_SUCCESS";
CASE_ERROR(ENOMEM, "Out of memory");
CASE_ERROR(ENOSPC, "Out of resources");
CASE_ERROR(EINVAL, "Invalid argument");
CASE_ERROR(ENOSYS, "Function not implemented");
CASE_ERROR(ENOENT, "No such file or directory");
CASE_ERROR(ENXIO, "No such device or address");
CASE_ERROR(EIO, "IO error");
CASE_ERROR(ESPIPE, "Illegal seek");
CASE_ERROR(ECORRUPT, "Data is corrupt");
CASE_ERROR(ENOTREADY, "Component is not ready");
CASE_ERROR(ECONFIG, "Component is not configured");
CASE_ERROR(EISCONN, "Port is already connected");
CASE_ERROR(ENOTCONN, "Port is disconnected");
CASE_ERROR(EAGAIN, "Resource temporarily unavailable");
CASE_ERROR(EFAULT, "Bad address");
case MMAL_STATUS_MAX: break; // Makes cpplint happy
}
return "Unknown error";
# undef CASE_ERROR
}
#undef LOG_ERROR_MMAL
#undef RUN

View File

@@ -1,70 +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/>. #
# #
*****************************************************************************/
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <linux/videodev2.h>
#include <interface/mmal/mmal.h>
#include <interface/mmal/mmal_format.h>
#include <interface/mmal/util/mmal_default_components.h>
#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"
typedef struct {
MMAL_WRAPPER_T *wrapper;
MMAL_PORT_T *input_port;
MMAL_PORT_T *output_port;
VCOS_SEMAPHORE_T handler_sem;
bool i_handler_sem;
frame_s *unjpegged;
int last_online;
unsigned i_width;
unsigned i_height;
unsigned i_format;
} h264_encoder_runtime_s;
typedef struct {
unsigned gop; // Interval between keyframes
unsigned bps; // Bit-per-sec
unsigned fps;
h264_encoder_runtime_s *run;
} h264_encoder_s;
h264_encoder_s *h264_encoder_init(void);
void h264_encoder_destroy(h264_encoder_s *encoder);
int h264_encoder_compress(h264_encoder_s *encoder, const frame_s *src, frame_s *dest);

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);