refactoring

This commit is contained in:
Devaev Maxim
2021-01-02 06:12:44 +03:00
parent 8222c17aa7
commit 6687548ba9
23 changed files with 177 additions and 247 deletions

View File

@@ -25,7 +25,6 @@
frame_s *frame_init(const char *role) {
frame_s *frame;
A_CALLOC(frame, 1);
frame->role = role;
frame->managed = true;
@@ -60,9 +59,7 @@ void frame_set_data(frame_s *frame, const uint8_t *data, size_t size) {
void frame_append_data(frame_s *frame, const uint8_t *data, size_t size) {
assert(frame->managed);
size_t new_used = frame->used + size;
frame_realloc_data(frame, new_used);
memcpy(frame->data + frame->used, data, size);
frame->used = new_used;

View File

@@ -98,9 +98,7 @@ INLINE long double get_now_real(void) {
}
INLINE unsigned get_cores_available(void) {
long cores_sysconf;
cores_sysconf = sysconf(_SC_NPROCESSORS_ONLN);
long cores_sysconf = sysconf(_SC_NPROCESSORS_ONLN);
cores_sysconf = (cores_sysconf < 0 ? 0 : cores_sysconf);
return max_u(min_u(cores_sysconf, 4), 1);
}

View File

@@ -40,11 +40,10 @@ static const char *_mmal_error_to_string(MMAL_STATUS_T error);
h264_encoder_s *h264_encoder_init(void) {
h264_encoder_runtime_s *run;
h264_encoder_s *encoder;
A_CALLOC(run, 1);
run->tmp = frame_init("h264_tmp");
h264_encoder_s *encoder;
A_CALLOC(encoder, 1);
encoder->gop = 60;
encoder->bps = 5000 * 1000; // Kbps * 1000
@@ -280,17 +279,13 @@ 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) {
MMAL_STATUS_T error;
MMAL_BUFFER_HEADER_T *out = NULL;
MMAL_BUFFER_HEADER_T *in = NULL;
bool eos = false;
bool sent = false;
assert(src->used > 0);
assert(src->width == encoder->width);
assert(src->height == encoder->height);
assert(src->format == encoder->format);
MMAL_STATUS_T error;
LOG_DEBUG("Compressing new H264 frame; force_key=%d ...", force_key);
frame_copy_meta(src, dest);
@@ -309,6 +304,11 @@ static int _h264_encoder_compress_raw(h264_encoder_s *encoder, const frame_s *sr
}
}
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) {

View File

@@ -33,20 +33,19 @@ static void _jpeg_error_handler(j_common_ptr jpeg);
int unjpeg(const frame_s *src, frame_s *dest) {
struct jpeg_decompress_struct jpeg;
_jpeg_error_manager_s jpeg_error;
JSAMPARRAY scanlines;
unsigned row_stride;
volatile int retval = 0;
struct jpeg_decompress_struct jpeg;
jpeg_create_decompress(&jpeg);
frame_realloc_data(dest, ((src->width * src->height) << 1) * 2);
frame_copy_meta(src, dest);
dest->format = V4L2_PIX_FMT_RGB24;
dest->used = 0;
jpeg_create_decompress(&jpeg);
// https://stackoverflow.com/questions/19857766/error-handling-in-libjpeg
_jpeg_error_manager_s jpeg_error;
jpeg.err = jpeg_std_error((struct jpeg_error_mgr *)&jpeg_error);
jpeg_error.mgr.error_exit = _jpeg_error_handler;
if (setjmp(jpeg_error.jmp) < 0) {
@@ -59,7 +58,9 @@ int unjpeg(const frame_s *src, frame_s *dest) {
jpeg.out_color_space = JCS_RGB;
jpeg_start_decompress(&jpeg);
row_stride = jpeg.output_width * jpeg.output_components;
const unsigned row_stride = jpeg.output_width * jpeg.output_components;
JSAMPARRAY scanlines;
scanlines = (*jpeg.mem->alloc_sarray)((j_common_ptr) &jpeg, JPOOL_IMAGE, row_stride, 1);
while (jpeg.output_scanline < jpeg.output_height) {

View File

@@ -29,8 +29,6 @@ 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;
@@ -48,6 +46,7 @@ memsink_s *memsink_open(const char *role, const char *name, bool server, mode_t
LOG_INFO("Using %s sink: %s.{mem,sig}", role, name);
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) { \
LOG_PERROR("Can't open %s sink signal semaphore", role); \
@@ -130,11 +129,11 @@ void memsink_close(memsink_s *memsink) {
free(memsink);
}
int memsink_server_put(memsink_s *memsink, frame_s *frame) {
long double now = get_now_monotonic();
int memsink_server_put(memsink_s *memsink, const frame_s *frame) {
assert(memsink->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->role, frame->used, MEMSINK_MAX_DATA);

View File

@@ -76,5 +76,5 @@ typedef struct {
memsink_s *memsink_open(const char *role, const char *name, bool server, mode_t mode, bool rm, unsigned timeout);
void memsink_close(memsink_s *memsink);
int memsink_server_put(memsink_s *memsink, frame_s *frame);
int memsink_server_put(memsink_s *memsink, const frame_s *frame);
int memsink_client_get(memsink_s *memsink, frame_s *frame);

View File

@@ -53,9 +53,7 @@ frame_s *blank_frame_init(const char *path) {
}
static frame_s *_init_internal(void) {
frame_s *blank;
blank = frame_init("blank_internal");
frame_s *blank = frame_init("blank_internal");
frame_set_data(blank, BLANK_JPEG_DATA, BLANK_JPEG_DATA_SIZE);
blank->width = BLANK_JPEG_WIDTH;
blank->height = BLANK_JPEG_HEIGHT;
@@ -65,9 +63,8 @@ static frame_s *_init_internal(void) {
static frame_s *_init_external(const char *path) {
FILE *fp = NULL;
frame_s *blank;
blank = frame_init("blank_external");
frame_s *blank = frame_init("blank_external");
blank->format = V4L2_PIX_FMT_JPEG;
if ((fp = fopen(path, "rb")) == NULL) {
@@ -118,11 +115,10 @@ static frame_s *_init_external(const char *path) {
static int _jpeg_read_geometry(FILE *fp, unsigned *width, unsigned *height) {
struct jpeg_decompress_struct jpeg;
_jpeg_error_manager_s jpeg_error;
jpeg_create_decompress(&jpeg);
// https://stackoverflow.com/questions/19857766/error-handling-in-libjpeg
_jpeg_error_manager_s jpeg_error;
jpeg.err = jpeg_std_error((struct jpeg_error_mgr *)&jpeg_error);
jpeg_error.mgr.error_exit = _jpeg_error_handler;
if (setjmp(jpeg_error.jmp) < 0) {

View File

@@ -84,11 +84,10 @@ static const char *_io_method_to_string_supported(enum v4l2_memory io_method);
device_s *device_init(void) {
device_runtime_s *run;
device_s *dev;
A_CALLOC(run, 1);
run->fd = -1;
device_s *dev;
A_CALLOC(dev, 1);
dev->path = "/dev/video0";
dev->width = 640;
@@ -226,7 +225,6 @@ int device_switch_capturing(device_s *dev, bool enable) {
}
int device_select(device_s *dev, bool *has_read, bool *has_write, bool *has_error) {
struct timeval timeout;
int retval;
# define INIT_FD_SET(_set) \
@@ -238,6 +236,7 @@ int device_select(device_s *dev, bool *has_read, bool *has_write, bool *has_erro
# undef INIT_FD_SET
struct timeval timeout;
timeout.tv_sec = dev->timeout;
timeout.tv_usec = 0;
@@ -273,7 +272,6 @@ int device_select(device_s *dev, bool *has_read, bool *has_write, bool *has_erro
int device_grab_buffer(device_s *dev) {
struct v4l2_buffer buf_info;
MEMSET_ZERO(buf_info);
buf_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf_info.memory = dev->io_method;
@@ -371,8 +369,6 @@ int device_consume_event(device_s *dev) {
static int _device_open_check_cap(device_s *dev) {
struct v4l2_capability cap;
int input = dev->input; // Needs pointer to int for ioctl()
MEMSET_ZERO(cap);
LOG_DEBUG("Calling ioctl(VIDIOC_QUERYCAP) ...");
@@ -391,6 +387,7 @@ static int _device_open_check_cap(device_s *dev) {
return -1;
}
int input = dev->input; // Needs a pointer to int for ioctl()
LOG_INFO("Using input channel: %d", input);
if (xioctl(RUN(fd), VIDIOC_S_INPUT, &input) < 0) {
LOG_ERROR("Can't set input channel");
@@ -434,7 +431,6 @@ static int _device_open_dv_timings(device_s *dev) {
static int _device_apply_dv_timings(device_s *dev) {
struct v4l2_dv_timings dv;
MEMSET_ZERO(dv);
LOG_DEBUG("Calling ioctl(VIDIOC_QUERY_DV_TIMINGS) ...");
@@ -467,7 +463,6 @@ static int _device_apply_dv_timings(device_s *dev) {
static int _device_open_format(device_s *dev) {
struct v4l2_format fmt;
MEMSET_ZERO(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = RUN(width);
@@ -518,10 +513,9 @@ static int _device_open_format(device_s *dev) {
}
static void _device_open_hw_fps(device_s *dev) {
struct v4l2_streamparm setfps;
RUN(hw_fps) = 0;
struct v4l2_streamparm setfps;
MEMSET_ZERO(setfps);
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -584,7 +578,6 @@ static int _device_open_io_method(device_s *dev) {
static int _device_open_io_method_mmap(device_s *dev) {
struct v4l2_requestbuffers req;
MEMSET_ZERO(req);
req.count = dev->n_buffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -608,7 +601,6 @@ static int _device_open_io_method_mmap(device_s *dev) {
A_CALLOC(RUN(hw_buffers), req.count);
for (RUN(n_buffers) = 0; RUN(n_buffers) < req.count; ++RUN(n_buffers)) {
struct v4l2_buffer buf_info;
MEMSET_ZERO(buf_info);
buf_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf_info.memory = V4L2_MEMORY_MMAP;
@@ -645,9 +637,6 @@ static int _device_open_io_method_mmap(device_s *dev) {
static int _device_open_io_method_userptr(device_s *dev) {
struct v4l2_requestbuffers req;
unsigned page_size = getpagesize();
unsigned buf_size = align_size(RUN(raw_size), page_size);
MEMSET_ZERO(req);
req.count = dev->n_buffers;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -669,13 +658,15 @@ static int _device_open_io_method_userptr(device_s *dev) {
LOG_DEBUG("Allocating device buffers ...");
A_CALLOC(RUN(hw_buffers), req.count);
const unsigned page_size = getpagesize();
const unsigned buf_size = align_size(RUN(raw_size), page_size);
for (RUN(n_buffers) = 0; RUN(n_buffers) < req.count; ++RUN(n_buffers)) {
# define HW(_next) RUN(hw_buffers)[RUN(n_buffers)]._next
assert(HW(raw.data) = aligned_alloc(page_size, buf_size));
memset(HW(raw.data), 0, buf_size);
HW(raw.allocated) = buf_size;
# undef HW
}
return 0;
@@ -684,7 +675,6 @@ static int _device_open_io_method_userptr(device_s *dev) {
static int _device_open_queue_buffers(device_s *dev) {
for (unsigned index = 0; index < RUN(n_buffers); ++index) {
struct v4l2_buffer buf_info;
MEMSET_ZERO(buf_info);
buf_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf_info.memory = dev->io_method;
@@ -795,8 +785,6 @@ static void _device_set_control(
device_s *dev, struct v4l2_queryctrl *query,
const char *name, unsigned cid, int value, bool quiet) {
struct v4l2_control ctl;
if (value < query->minimum || value > query->maximum || value % query->step != 0) {
if (!quiet) {
LOG_ERROR("Invalid value %d of control %s: min=%d, max=%d, default=%d, step=%u",
@@ -805,6 +793,7 @@ static void _device_set_control(
return;
}
struct v4l2_control ctl;
MEMSET_ZERO(ctl);
ctl.id = cid;
ctl.value = value;

View File

@@ -44,13 +44,12 @@ static const struct {
encoder_s *encoder_init(void) {
encoder_runtime_s *run;
encoder_s *encoder;
A_CALLOC(run, 1);
run->type = ENCODER_TYPE_CPU;
run->quality = 80;
A_MUTEX_INIT(&run->mutex);
encoder_s *encoder;
A_CALLOC(encoder, 1);
encoder->type = run->type;
encoder->quality = run->quality;

View File

@@ -37,21 +37,10 @@ typedef struct {
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, frame_s *frame);
static void _jpeg_write_scanlines_yuyv(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height);
static void _jpeg_write_scanlines_uyvy(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height);
static void _jpeg_write_scanlines_rgb565(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height);
static void _jpeg_write_scanlines_rgb24(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height);
static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg, const frame_s *frame);
static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg, const frame_s *frame);
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const frame_s *frame);
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const frame_s *frame);
static void _jpeg_init_destination(j_compress_ptr jpeg);
static boolean _jpeg_empty_output_buffer(j_compress_ptr jpeg);
@@ -80,7 +69,7 @@ void cpu_encoder_compress(frame_s *src, frame_s *dest, unsigned quality) {
jpeg_start_compress(&jpeg, TRUE);
# define WRITE_SCANLINES(_format, _func) \
case _format: { _func(&jpeg, src->data, src->width, src->height); break; }
case _format: { _func(&jpeg, src); break; }
switch (src->format) {
// https://www.fourcc.org/yuv.php
@@ -100,15 +89,13 @@ void cpu_encoder_compress(frame_s *src, frame_s *dest, unsigned quality) {
}
static void _jpeg_set_dest_frame(j_compress_ptr jpeg, frame_s *frame) {
_jpeg_dest_manager_s *dest;
if (jpeg->dest == NULL) {
assert((jpeg->dest = (struct jpeg_destination_mgr *)(*jpeg->mem->alloc_small)(
(j_common_ptr) jpeg, JPOOL_PERMANENT, sizeof(_jpeg_dest_manager_s)
)));
}
dest = (_jpeg_dest_manager_s *)jpeg->dest;
_jpeg_dest_manager_s *dest = (_jpeg_dest_manager_s *)jpeg->dest;
dest->mgr.init_destination = _jpeg_init_destination;
dest->mgr.empty_output_buffer = _jpeg_empty_output_buffer;
dest->mgr.term_destination = _jpeg_term_destination;
@@ -122,20 +109,17 @@ static void _jpeg_set_dest_frame(j_compress_ptr jpeg, frame_s *frame) {
#define YUV_B(_y, _u, _) (((_y) + (454 * (_u))) >> 8)
#define NORM_COMPONENT(_x) (((_x) > 255) ? 255 : (((_x) < 0) ? 0 : (_x)))
static void _jpeg_write_scanlines_yuyv(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height) {
static void _jpeg_write_scanlines_yuyv(struct jpeg_compress_struct *jpeg, const frame_s *frame) {
uint8_t *line_buffer;
JSAMPROW scanlines[1];
A_CALLOC(line_buffer, frame->width * 3);
const uint8_t *data = frame->data;
unsigned z = 0;
A_CALLOC(line_buffer, width * 3);
while (jpeg->next_scanline < height) {
while (jpeg->next_scanline < frame->height) {
uint8_t *ptr = line_buffer;
for (unsigned x = 0; x < width; ++x) {
for (unsigned x = 0; x < frame->width; ++x) {
int y = (!z ? data[0] << 8 : data[2] << 8);
int u = data[1] - 128;
int v = data[3] - 128;
@@ -154,6 +138,7 @@ static void _jpeg_write_scanlines_yuyv(
}
}
JSAMPROW scanlines[1];
scanlines[0] = line_buffer;
jpeg_write_scanlines(jpeg, scanlines, 1);
}
@@ -161,20 +146,17 @@ static void _jpeg_write_scanlines_yuyv(
free(line_buffer);
}
static void _jpeg_write_scanlines_uyvy(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height) {
static void _jpeg_write_scanlines_uyvy(struct jpeg_compress_struct *jpeg, const frame_s *frame) {
uint8_t *line_buffer;
JSAMPROW scanlines[1];
A_CALLOC(line_buffer, frame->width * 3);
const uint8_t *data = frame->data;
unsigned z = 0;
A_CALLOC(line_buffer, width * 3);
while (jpeg->next_scanline < height) {
while (jpeg->next_scanline < frame->height) {
uint8_t *ptr = line_buffer;
for(unsigned x = 0; x < width; ++x) {
for(unsigned x = 0; x < frame->width; ++x) {
int y = (!z ? data[1] << 8 : data[3] << 8);
int u = data[0] - 128;
int v = data[2] - 128;
@@ -193,6 +175,7 @@ static void _jpeg_write_scanlines_uyvy(
}
}
JSAMPROW scanlines[1];
scanlines[0] = line_buffer;
jpeg_write_scanlines(jpeg, scanlines, 1);
}
@@ -205,19 +188,16 @@ static void _jpeg_write_scanlines_uyvy(
#undef YUV_G
#undef YUV_R
static void _jpeg_write_scanlines_rgb565(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height) {
static void _jpeg_write_scanlines_rgb565(struct jpeg_compress_struct *jpeg, const frame_s *frame) {
uint8_t *line_buffer;
JSAMPROW scanlines[1];
A_CALLOC(line_buffer, frame->width * 3);
A_CALLOC(line_buffer, width * 3);
const uint8_t *data = frame->data;
while (jpeg->next_scanline < height) {
while (jpeg->next_scanline < frame->height) {
uint8_t *ptr = line_buffer;
for(unsigned x = 0; x < width; ++x) {
for(unsigned x = 0; x < frame->width; ++x) {
unsigned int two_byte = (data[1] << 8) + data[0];
*(ptr++) = data[1] & 248; // Red
@@ -227,6 +207,7 @@ static void _jpeg_write_scanlines_rgb565(
data += 2;
}
JSAMPROW scanlines[1];
scanlines[0] = line_buffer;
jpeg_write_scanlines(jpeg, scanlines, 1);
}
@@ -234,14 +215,10 @@ static void _jpeg_write_scanlines_rgb565(
free(line_buffer);
}
static void _jpeg_write_scanlines_rgb24(
struct jpeg_compress_struct *jpeg, const uint8_t *data,
unsigned width, unsigned height) {
JSAMPROW scanlines[1];
while (jpeg->next_scanline < height) {
scanlines[0] = (uint8_t *)(data + jpeg->next_scanline * width * 3);
static void _jpeg_write_scanlines_rgb24(struct jpeg_compress_struct *jpeg, const frame_s *frame) {
while (jpeg->next_scanline < frame->height) {
JSAMPROW scanlines[1];
scanlines[0] = (uint8_t *)(frame->data + jpeg->next_scanline * frame->width * 3);
jpeg_write_scanlines(jpeg, scanlines, 1);
}
}

View File

@@ -34,7 +34,6 @@ static bool _is_huffman(const uint8_t *data);
int hw_encoder_prepare(device_s *dev, unsigned quality) {
struct v4l2_jpegcompression comp;
MEMSET_ZERO(comp);
if (xioctl(dev->run->fd, VIDIOC_G_JPEGCOMP, &comp) < 0) {
@@ -60,7 +59,6 @@ void _copy_plus_huffman(const frame_s *src, frame_s *dest) {
if (!_is_huffman(src->data)) {
const uint8_t *src_ptr = src->data;
const uint8_t *src_end = src->data + src->used;
size_t paste;
while ((((src_ptr[0] << 8) | src_ptr[1]) != 0xFFC0) && (src_ptr < src_end)) {
src_ptr += 1;
@@ -69,7 +67,8 @@ void _copy_plus_huffman(const frame_s *src, frame_s *dest) {
dest->used = 0; // Error
return;
}
paste = src_ptr - src->data;
const size_t paste = src_ptr - src->data;
frame_set_data(dest, src->data, paste);
frame_append_data(dest, HUFFMAN_TABLE, sizeof(HUFFMAN_TABLE));

View File

@@ -78,10 +78,10 @@ int component_set_portdef(OMX_HANDLETYPE *component, OMX_PARAM_PORTDEFINITIONTYP
int component_set_state(OMX_HANDLETYPE *component, OMX_STATETYPE state) {
const char *state_str = omx_state_to_string(state);
OMX_ERRORTYPE error;
int retries = 50;
LOG_DEBUG("Switching component state to %s ...", state_str);
int retries = 50;
do {
error = OMX_SendCommand(*component, OMX_CommandStateSet, state, NULL);
if (error == OMX_ErrorNone) {
@@ -103,12 +103,12 @@ int component_set_state(OMX_HANDLETYPE *component, OMX_STATETYPE state) {
static int _component_wait_port_changed(OMX_HANDLETYPE *component, OMX_U32 port, OMX_BOOL enabled) {
OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
int retries = 50;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
OMX_INIT_STRUCTURE(portdef);
portdef.nPortIndex = port;
int retries = 50;
do {
if ((error = OMX_GetParameter(*component, OMX_IndexParamPortDefinition, &portdef)) != OMX_ErrorNone) {
LOG_ERROR_OMX(error, "Can't get OMX port %u definition for waiting", port);
@@ -129,8 +129,8 @@ static int _component_wait_port_changed(OMX_HANDLETYPE *component, OMX_U32 port,
static int _component_wait_state_changed(OMX_HANDLETYPE *component, OMX_STATETYPE wanted) {
OMX_ERRORTYPE error;
OMX_STATETYPE state;
int retries = 50;
int retries = 50;
do {
if ((error = OMX_GetState(*component, &state)) != OMX_ErrorNone) {
LOG_ERROR_OMX(error, "Failed to get OMX component state");

View File

@@ -63,8 +63,6 @@ omx_encoder_s *omx_encoder_init(void) {
// - http://home.nouwen.name/RaspberryPi/documentation/ilcomponents/image_encode.html
omx_encoder_s *omx;
OMX_ERRORTYPE error;
A_CALLOC(omx, 1);
assert(_i_omx >= 0);
@@ -73,7 +71,7 @@ omx_encoder_s *omx_encoder_init(void) {
bcm_host_init();
LOG_INFO("Initializing OMX ...");
if ((error = OMX_Init()) != OMX_ErrorNone) {
if ((OMX_ERRORTYPE error = OMX_Init()) != OMX_ErrorNone) {
LOG_ERROR_OMX(error, "Can't initialize OMX");
goto error;
}
@@ -104,8 +102,6 @@ omx_encoder_s *omx_encoder_init(void) {
}
void omx_encoder_destroy(omx_encoder_s *omx) {
OMX_ERRORTYPE error;
LOG_INFO("Destroying OMX encoder ...");
component_set_state(&omx->encoder, OMX_StateIdle);
@@ -117,7 +113,7 @@ void omx_encoder_destroy(omx_encoder_s *omx) {
}
if (omx->i_encoder) {
if ((error = OMX_FreeHandle(omx->encoder)) != OMX_ErrorNone) {
if ((OMX_ERRORTYPE error = OMX_FreeHandle(omx->encoder)) != OMX_ErrorNone) {
LOG_ERROR_OMX(error, "Can't free OMX.broadcom.image_encode");
}
}
@@ -159,8 +155,6 @@ int omx_encoder_compress(omx_encoder_s *omx, frame_s *src, frame_s *dest) {
# define OUT(_next) omx->output_buffer->_next
OMX_ERRORTYPE error;
size_t slice_size = (IN(nAllocLen) < src->used ? IN(nAllocLen) : src->used);
size_t pos = 0;
if ((error = OMX_FillThisBuffer(omx->encoder, omx->output_buffer)) != OMX_ErrorNone) {
LOG_ERROR_OMX(error, "Failed to request filling of the output buffer on encoder");
@@ -171,6 +165,9 @@ int omx_encoder_compress(omx_encoder_s *omx, frame_s *src, frame_s *dest) {
omx->output_available = false;
omx->input_required = true;
const size_t slice_size = (IN(nAllocLen) < src->used ? IN(nAllocLen) : src->used);
size_t pos = 0;
while (true) {
if (omx->failed) {
return -1;

View File

@@ -40,8 +40,8 @@ static const unsigned _MOD_TABLE[] = {0, 2, 1};
char *base64_encode(const uint8_t *str) {
size_t str_len = strlen((const char *)str);
size_t encoded_size = 4 * ((str_len + 2) / 3) + 1; // +1 for '\0'
char *encoded;
char *encoded;
A_CALLOC(encoded, encoded_size);
for (unsigned str_index = 0, encoded_index = 0; str_index < str_len;) {

View File

@@ -47,16 +47,13 @@ static const struct {
const char *guess_mime_type(const char *path) {
char *dot;
char *ext;
// FIXME: false-positive cppcheck
dot = strrchr(path, '.'); // cppcheck-suppress ctunullpointer
char *dot = strrchr(path, '.'); // cppcheck-suppress ctunullpointer
if (dot == NULL || strchr(dot, '/') != NULL) {
goto misc;
}
ext = dot + 1;
char *ext = dot + 1;
for (unsigned index = 0; index < ARRAY_LEN(_MIME_TYPES); ++index) {
if (!evutil_ascii_strcasecmp(ext, _MIME_TYPES[index].ext)) {
return _MIME_TYPES[index].mime;

View File

@@ -48,17 +48,16 @@ static void _format_bufferevent_reason(short what, char *reason);
server_s *server_init(stream_s *stream) {
server_runtime_s *run;
server_s *server;
exposed_s *exposed;
A_CALLOC(exposed, 1);
exposed->frame = frame_init("http_exposed");
server_runtime_s *run;
A_CALLOC(run, 1);
run->stream = stream;
run->exposed = exposed;
server_s *server;
A_CALLOC(server, 1);
server->host = "127.0.0.1";
server->port = 8080;
@@ -95,7 +94,6 @@ void server_destroy(server_s *server) {
for (stream_client_s *client = RUN(stream_clients); client != NULL;) {
stream_client_s *next = client->next;
free(client->key);
free(client);
client = next;
@@ -233,20 +231,19 @@ static int _http_preprocess_request(struct evhttp_request *request, server_s *se
static void _http_callback_root(struct evhttp_request *request, void *v_server) {
server_s *server = (server_s *)v_server;
struct evbuffer *buf;
struct evkeyvalq params; // For mjpg-streamer compatibility
const char *action; // Ditto
PREPROCESS_REQUEST;
struct evkeyvalq params; // For mjpg-streamer compatibility
evhttp_parse_query(evhttp_request_get_uri(request), &params);
action = evhttp_find_header(&params, "action");
const char *action = evhttp_find_header(&params, "action");
if (action && !strcmp(action, "snapshot")) {
_http_callback_snapshot(request, v_server);
} else if (action && !strcmp(action, "stream")) {
_http_callback_stream(request, v_server);
} else {
struct evbuffer *buf;
assert((buf = evbuffer_new()));
assert(evbuffer_add_printf(buf, "%s", HTML_INDEX_PAGE));
ADD_HEADER("Content-Type", "text/html");
@@ -261,23 +258,25 @@ static void _http_callback_static(struct evhttp_request *request, void *v_server
server_s *server = (server_s *)v_server;
struct evbuffer *buf = NULL;
struct evhttp_uri *uri = NULL;
char *uri_path;
char *decoded_path = NULL;
char *static_path = NULL;
int fd = -1;
struct stat st;
PREPROCESS_REQUEST;
if ((uri = evhttp_uri_parse(evhttp_request_get_uri(request))) == NULL) {
goto bad_request;
}
if ((uri_path = (char *)evhttp_uri_get_path(uri)) == NULL) {
uri_path = "/";
}
{
char *uri_path;
if ((decoded_path = evhttp_uridecode(uri_path, 0, NULL)) == NULL) {
goto bad_request;
if ((uri = evhttp_uri_parse(evhttp_request_get_uri(request))) == NULL) {
goto bad_request;
}
if ((uri_path = (char *)evhttp_uri_get_path(uri)) == NULL) {
uri_path = "/";
}
if ((decoded_path = evhttp_uridecode(uri_path, 0, NULL)) == NULL) {
goto bad_request;
}
}
assert((buf = evbuffer_new()));
@@ -291,18 +290,22 @@ static void _http_callback_static(struct evhttp_request *request, void *v_server
goto not_found;
}
if (fstat(fd, &st) < 0) {
LOG_PERROR("HTTP: Can't stat() found static file %s", static_path);
goto not_found;
}
{
struct stat st;
if (st.st_size > 0 && evbuffer_add_file(buf, fd, 0, st.st_size) < 0) {
LOG_ERROR("HTTP: Can't serve static file %s", static_path);
goto not_found;
if (fstat(fd, &st) < 0) {
LOG_PERROR("HTTP: Can't stat() found static file %s", static_path);
goto not_found;
}
if (st.st_size > 0 && evbuffer_add_file(buf, fd, 0, st.st_size) < 0) {
LOG_ERROR("HTTP: Can't serve static file %s", static_path);
goto not_found;
}
ADD_HEADER("Content-Type", guess_mime_type(static_path));
evhttp_send_reply(request, HTTP_OK, "OK", buf);
goto cleanup;
}
ADD_HEADER("Content-Type", guess_mime_type(static_path));
evhttp_send_reply(request, HTTP_OK, "OK", buf);
goto cleanup;
bad_request:
evhttp_send_error(request, HTTP_BADREQUEST, NULL);
@@ -332,14 +335,14 @@ static void _http_callback_static(struct evhttp_request *request, void *v_server
static void _http_callback_state(struct evhttp_request *request, void *v_server) {
server_s *server = (server_s *)v_server;
struct evbuffer *buf;
encoder_type_e encoder_type;
unsigned encoder_quality;
PREPROCESS_REQUEST;
encoder_type_e encoder_type;
unsigned encoder_quality;
encoder_get_runtime_params(STREAM(encoder), &encoder_type, &encoder_quality);
struct evbuffer *buf;
assert((buf = evbuffer_new()));
assert(evbuffer_add_printf(buf,
@@ -380,11 +383,10 @@ static void _http_callback_state(struct evhttp_request *request, void *v_server)
static void _http_callback_snapshot(struct evhttp_request *request, void *v_server) {
server_s *server = (server_s *)v_server;
struct evbuffer *buf;
char header_buf[64];
PREPROCESS_REQUEST;
struct evbuffer *buf;
assert((buf = evbuffer_new()));
assert(!evbuffer_add(buf, (const void *)EX(frame->data), EX(frame->used)));
@@ -395,6 +397,8 @@ static void _http_callback_snapshot(struct evhttp_request *request, void *v_serv
ADD_HEADER("Pragma", "no-cache");
ADD_HEADER("Expires", "Mon, 3 Jan 2000 12:34:56 GMT");
char header_buf[256];
# define ADD_TIME_HEADER(_key, _value) { \
sprintf(header_buf, "%.06Lf", _value); \
ADD_HEADER(_key, header_buf); \
@@ -438,24 +442,21 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
// https://github.com/libevent/libevent/blob/29cc8386a2f7911eaa9336692a2c5544d8b4734f/http.c#L1458
server_s *server = (server_s *)v_server;
struct evhttp_connection *conn;
struct evkeyvalq params;
struct bufferevent *buf_event;
stream_client_s *client;
char *client_addr;
unsigned short client_port;
uuid_t uuid;
PREPROCESS_REQUEST;
struct evhttp_connection *conn;
conn = evhttp_request_get_connection(request);
if (conn) {
stream_client_s *client;
A_CALLOC(client, 1);
client->server = server;
client->request = request;
client->need_initial = true;
client->need_first_frame = true;
struct evkeyvalq params;
evhttp_parse_query(evhttp_request_get_uri(request), &params);
client->key = uri_get_string(&params, "key");
client->extra_headers = uri_get_true(&params, "extra_headers");
@@ -463,6 +464,7 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
client->dual_final_frames = uri_get_true(&params, "dual_final_frames");
evhttp_clear_headers(&params);
uuid_t uuid;
uuid_generate(uuid);
uuid_unparse_lower(uuid, client->id);
@@ -487,11 +489,15 @@ static void _http_callback_stream(struct evhttp_request *request, void *v_server
# endif
}
char *client_addr;
unsigned short client_port;
evhttp_connection_get_peer(conn, &client_addr, &client_port);
LOG_INFO("HTTP: Registered client: [%s]:%u, id=%s; clients now: %u",
client_addr, client_port, client->id, RUN(stream_clients_count));
buf_event = evhttp_connection_get_bufferevent(conn);
struct bufferevent *buf_event = evhttp_connection_get_bufferevent(conn);
if (server->tcp_nodelay && !RUN(unix_fd)) {
evutil_socket_t fd;
int on = 1;
@@ -517,7 +523,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
stream_client_s *client = (stream_client_s *)v_client;
server_s *server = client->server;
struct evbuffer *buf;
long double now = get_now_monotonic();
long long now_second = floor_ms(now);
@@ -528,6 +534,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
}
client->fps_accum += 1;
struct evbuffer *buf;
assert((buf = evbuffer_new()));
// В хроме и его производных есть фундаментальный баг: он отрисовывает
@@ -640,11 +647,8 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UNUSED short what, void *v_client) {
stream_client_s *client = (stream_client_s *)v_client;
server_s *server = client->server;
struct evhttp_connection *conn;
char *client_addr = "???";
unsigned short client_port = 0;
char reason[2048] = {0};
char reason[2048] = {0};
_format_bufferevent_reason(what, reason);
assert(RUN(stream_clients_count) > 0);
@@ -660,13 +664,17 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN
# endif
}
conn = evhttp_request_get_connection(client->request);
char *client_addr = "???";
unsigned short client_port = 0;
struct evhttp_connection *conn = evhttp_request_get_connection(client->request);
if (conn) {
evhttp_connection_get_peer(conn, &client_addr, &client_port);
}
LOG_INFO("HTTP: Disconnected client: [%s]:%u, id=%s, %s; clients now: %u",
client_addr, client_port, client->id, reason, RUN(stream_clients_count));
if (conn) {
evhttp_connection_free(conn);
}
@@ -684,14 +692,11 @@ static void _http_callback_stream_error(UNUSED struct bufferevent *buf_event, UN
}
static void _http_queue_send_stream(server_s *server, bool stream_updated, bool frame_updated) {
struct evhttp_connection *conn;
struct bufferevent *buf_event;
long long now;
bool has_clients = false;
bool queued = false;
for (stream_client_s *client = RUN(stream_clients); client != NULL; client = client->next) {
conn = evhttp_request_get_connection(client->request);
struct evhttp_connection *conn = evhttp_request_get_connection(client->request);
if (conn) {
// Фикс для бага WebKit. При включенной опции дропа одинаковых фреймов,
// WebKit отрисовывает последний фрейм в серии с некоторой задержкой,
@@ -708,7 +713,7 @@ static void _http_queue_send_stream(server_s *server, bool stream_updated, bool
);
if (dual_update || frame_updated || client->need_first_frame) {
buf_event = evhttp_connection_get_bufferevent(conn);
struct bufferevent *buf_event = evhttp_connection_get_bufferevent(conn);
bufferevent_setcb(buf_event, NULL, _http_callback_stream_write, _http_callback_stream_error, (void *)client);
bufferevent_enable(buf_event, EV_READ|EV_WRITE);
@@ -726,8 +731,8 @@ static void _http_queue_send_stream(server_s *server, bool stream_updated, bool
if (queued) {
static unsigned queued_fps_accum = 0;
static long long queued_fps_second = 0;
if ((now = floor_ms(get_now_monotonic())) != queued_fps_second) {
long long now = floor_ms(get_now_monotonic());
if (now != queued_fps_second) {
EX(queued_fps) = queued_fps_accum;
queued_fps_accum = 0;
queued_fps_second = now;

View File

@@ -24,11 +24,9 @@
char *find_static_file_path(const char *root_path, const char *request_path) {
char *simplified_path;
char *path = NULL;
struct stat st;
simplified_path = simplify_request_path(request_path);
char *simplified_path = simplify_request_path(request_path);
if (simplified_path[0] == '\0') {
LOG_VERBOSE("HTTP: Invalid request path %s to static", request_path);
goto error;
@@ -37,6 +35,7 @@ char *find_static_file_path(const char *root_path, const char *request_path) {
A_CALLOC(path, strlen(root_path) + strlen(simplified_path) + 32);
sprintf(path, "%s/%s", root_path, simplified_path);
struct stat st;
# define LOAD_STAT { \
if (lstat(path, &st) < 0) { \
LOG_VERBOSE_PERROR("HTTP: Can't stat() static path %s", path); \

View File

@@ -24,7 +24,6 @@
evutil_socket_t evhttp_my_bind_unix(struct evhttp *http, const char *path, bool rm, mode_t mode) {
evutil_socket_t fd = -1;
struct sockaddr_un addr;
# define MAX_SUN_PATH (sizeof(addr.sun_path) - 1)
@@ -40,6 +39,7 @@ evutil_socket_t evhttp_my_bind_unix(struct evhttp *http, const char *path, bool
# undef MAX_SUN_PATH
evutil_socket_t fd = -1;
assert((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);
assert(!evutil_make_socket_nonblocking(fd));

View File

@@ -24,9 +24,8 @@
bool uri_get_true(struct evkeyvalq *params, const char *key) {
const char *value_str;
if ((value_str = evhttp_find_header(params, key)) != NULL) {
const char *value_str = evhttp_find_header(params, key);
if (value_str != NULL) {
if (
value_str[0] == '1'
|| !evutil_ascii_strcasecmp(value_str, "true")
@@ -39,9 +38,8 @@ bool uri_get_true(struct evkeyvalq *params, const char *key) {
}
char *uri_get_string(struct evkeyvalq *params, const char *key) {
const char *value_str;
if ((value_str = evhttp_find_header(params, key)) != NULL) {
const char *value_str = evhttp_find_header(params, key);
if (value_str != NULL) {
return evhttp_encode_uri(value_str);
}
return NULL;

View File

@@ -87,8 +87,8 @@ static void _signal_handler(int signum) {
static void _install_signal_handlers(void) {
struct sigaction sig_act;
MEMSET_ZERO(sig_act);
assert(!sigemptyset(&sig_act.sa_mask));
sig_act.sa_handler = _signal_handler;
assert(!sigaddset(&sig_act.sa_mask, SIGINT));
@@ -105,21 +105,18 @@ static void _install_signal_handlers(void) {
}
int main(int argc, char *argv[]) {
options_s *options;
device_s *dev;
encoder_s *encoder;
stream_s *stream;
server_s *server;
int exit_code = 0;
assert(argc >= 0);
LOGGING_INIT;
A_THREAD_RENAME("main");
options = options_init(argc, argv);
dev = device_init();
encoder = encoder_init();
stream = stream_init(dev, encoder);
server = server_init(stream);
options_s *options = options_init(argc, argv);
device_s *dev = device_init();
encoder_s *encoder = encoder_init();
stream_s *stream = stream_init(dev, encoder);
server_s *server = server_init(stream);
int exit_code = 0;
if ((exit_code = options_parse(options, dev, encoder, stream, server)) == 0) {
# ifdef WITH_GPIO
@@ -128,10 +125,7 @@ int main(int argc, char *argv[]) {
_install_signal_handlers();
pthread_t stream_loop_tid;
pthread_t server_loop_tid;
_main_context_s ctx;
ctx.stream = stream;
ctx.server = server;
_ctx = &ctx;
@@ -141,6 +135,8 @@ int main(int argc, char *argv[]) {
gpio_set_prog_running(true);
# endif
pthread_t stream_loop_tid;
pthread_t server_loop_tid;
A_THREAD_CREATE(&stream_loop_tid, _stream_loop_thread, NULL);
A_THREAD_CREATE(&server_loop_tid, _server_loop_thread, NULL);
A_THREAD_JOIN(server_loop_tid);

View File

@@ -214,18 +214,16 @@ static void _features(void);
static void _help(device_s *dev, encoder_s *encoder, stream_s *stream, server_s *server);
options_s *options_init(int argc, char *argv[]) {
options_s *options_init(unsigned argc, char *argv[]) {
options_s *options;
A_CALLOC(options, 1);
options->argc = argc;
options->argv = argv;
A_CALLOC(options->argv_copy, argc);
for (int index = 0; index < argc; ++index) {
for (unsigned index = 0; index < argc; ++index) {
assert(options->argv_copy[index] = strdup(argv[index]));
}
return options;
}
@@ -238,7 +236,7 @@ void options_destroy(options_s *options) {
if (options->blank) {
frame_destroy(options->blank);
}
for (int index = 0; index < options->argc; ++index) {
for (unsigned index = 0; index < options->argc; ++index) {
free(options->argv_copy[index]);
}
free(options->argv_copy);
@@ -313,11 +311,6 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
break; \
}
int ch;
int short_index;
int opt_index;
char short_opts[1024] = {0};
char *blank_path = NULL;
# ifdef WITH_MEMSINK
@@ -331,7 +324,9 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
char *process_name_prefix = NULL;
# endif
for (short_index = 0, opt_index = 0; _LONG_OPTS[opt_index].name != NULL; ++opt_index) {
char short_opts[1024] = {0};
for (int short_index = 0, opt_index = 0; _LONG_OPTS[opt_index].name != NULL; ++opt_index) {
if (isalpha(_LONG_OPTS[opt_index].val)) {
short_opts[short_index] = _LONG_OPTS[opt_index].val;
++short_index;
@@ -342,7 +337,7 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
}
}
while ((ch = getopt_long(options->argc, options->argv_copy, short_opts, _LONG_OPTS, NULL)) >= 0) {
for (int ch; (ch = getopt_long(options->argc, options->argv_copy, short_opts, _LONG_OPTS, NULL)) >= 0;) {
switch (ch) {
case _O_DEVICE: OPT_SET(dev->path, optarg);
case _O_INPUT: OPT_NUMBER("--input", dev->input, 0, 128, 0);
@@ -494,7 +489,6 @@ int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_
static int _parse_resolution(const char *str, unsigned *width, unsigned *height, bool limited) {
unsigned tmp_width;
unsigned tmp_height;
if (sscanf(str, "%ux%u", &tmp_width, &tmp_height) != 2) {
return -1;
}
@@ -514,20 +508,19 @@ static int _parse_resolution(const char *str, unsigned *width, unsigned *height,
#ifdef WITH_OMX
static int _parse_glitched_resolutions(const char *str, encoder_s *encoder) {
char *str_copy;
char *ptr;
unsigned count = 0;
unsigned width;
unsigned height;
assert((str_copy = strdup(str)) != NULL);
ptr = strtok(str_copy, ",;:\n\t ");
char *ptr = strtok(str_copy, ",;:\n\t ");
unsigned count = 0;
while (ptr != NULL) {
if (count >= MAX_GLITCHED_RESOLUTIONS) {
printf("Too big '--glitched-resolutions' list: maxlen=%u\n", MAX_GLITCHED_RESOLUTIONS);
goto error;
}
unsigned width;
unsigned height;
switch (_parse_resolution(ptr, &width, &height, true)) {
case -1:
printf("Invalid resolution format of '%s' in '--glitched-resolutions=%s\n", ptr, str_copy);

View File

@@ -52,7 +52,7 @@
typedef struct {
int argc;
unsigned argc;
char **argv;
char **argv_copy;
frame_s *blank;
@@ -62,7 +62,7 @@ typedef struct {
} options_s;
options_s *options_init(int argc, char *argv[]);
options_s *options_init(unsigned argc, char *argv[]);
void options_destroy(options_s *options);
int options_parse(options_s *options, device_s *dev, encoder_s *encoder, stream_s *stream, server_s *server);

View File

@@ -85,18 +85,17 @@ static long double _workers_pool_get_fluency_delay(_pool_s *pool, _worker_s *rea
stream_s *stream_init(device_s *dev, encoder_s *encoder) {
process_s *proc;
video_s *video;
stream_s *stream;
A_CALLOC(proc, 1);
atomic_init(&proc->stop, false);
atomic_init(&proc->slowdown, false);
video_s *video;
A_CALLOC(video, 1);
video->frame = frame_init("stream_video");
atomic_init(&video->updated, false);
A_MUTEX_INIT(&video->mutex);
stream_s *stream;
A_CALLOC(stream, 1);
stream->last_as_blank = -1;
stream->error_delay = 1;
@@ -117,12 +116,11 @@ void stream_destroy(stream_s *stream) {
void stream_loop(stream_s *stream) {
# define DEV(_next) stream->dev->_next
_pool_s *pool;
LOG_INFO("Using V4L2 device: %s", DEV(path));
LOG_INFO("Using desired FPS: %u", DEV(desired_fps));
while ((pool = _stream_init_loop(stream)) != NULL) {
for (_pool_s *pool; (pool = _stream_init_loop(stream)) != NULL;) {
long double grab_after = 0;
unsigned fluency_passed = 0;
unsigned captured_fps = 0;
@@ -132,12 +130,10 @@ void stream_loop(stream_s *stream) {
LOG_INFO("Capturing ...");
while (!atomic_load(&stream->proc->stop)) {
_worker_s *ready_wr;
SEP_DEBUG('-');
LOG_DEBUG("Waiting for worker ...");
ready_wr = _workers_pool_wait(pool);
_worker_s *ready_wr = _workers_pool_wait(pool);
if (!ready_wr->job_failed) {
if (ready_wr->job_timely) {
@@ -373,10 +369,9 @@ static _pool_s *_workers_pool_init(stream_s *stream) {
# define DEV(_next) stream->dev->_next
# define RUN(_next) stream->dev->run->_next
_pool_s *pool;
LOG_INFO("Creating pool with %u workers ...", stream->encoder->run->n_workers);
_pool_s *pool;
A_CALLOC(pool, 1);
pool->n_workers = stream->encoder->run->n_workers;
@@ -470,7 +465,6 @@ static void *_worker_thread(void *v_worker) {
# define PIC(_next) wr->frame->_next
LOG_DEBUG("Worker %u compressing JPEG from buffer %u ...", wr->number, wr->buf_index);
wr->job_failed = (bool)encoder_compress(
wr->stream->encoder,
wr->number,
@@ -482,7 +476,6 @@ static void *_worker_thread(void *v_worker) {
if (!wr->job_failed) {
wr->job_start_ts = PIC(encode_begin_ts);
wr->last_comp_time = PIC(encode_end_ts) - wr->job_start_ts;
LOG_VERBOSE("Compressed new JPEG: size=%zu, time=%0.3Lf, worker=%u, buffer=%u",
PIC(used), wr->last_comp_time, wr->number, wr->buf_index);
} else {
@@ -567,17 +560,14 @@ static void _workers_pool_assign(_pool_s *pool, _worker_s *ready_wr, unsigned bu
}
static long double _workers_pool_get_fluency_delay(_pool_s *pool, _worker_s *ready_wr) {
long double approx_comp_time;
long double min_delay;
approx_comp_time = pool->approx_comp_time * 0.9 + ready_wr->last_comp_time * 0.1;
const long double approx_comp_time = pool->approx_comp_time * 0.9 + ready_wr->last_comp_time * 0.1;
LOG_VERBOSE("Correcting approx_comp_time: %.3Lf -> %.3Lf (last_comp_time=%.3Lf)",
pool->approx_comp_time, approx_comp_time, ready_wr->last_comp_time);
pool->approx_comp_time = approx_comp_time;
min_delay = pool->approx_comp_time / pool->n_workers; // Среднее время работы размазывается на N воркеров
const long double min_delay = pool->approx_comp_time / pool->n_workers; // Среднее время работы размазывается на N воркеров
if (pool->desired_frames_interval > 0 && min_delay > 0 && pool->desired_frames_interval > min_delay) {
// Искусственное время задержки на основе желаемого FPS, если включен --desired-fps