Compare commits

...

16 Commits
v0.35 ... v0.41

Author SHA1 Message Date
Devaev Maxim
8e61d7c55e Bump version: 0.40 → 0.41 2018-11-12 11:37:09 +03:00
Devaev Maxim
4e42c42bae always use ijg 2018-11-12 11:36:56 +03:00
Devaev Maxim
b53e3edef1 updated readme 2018-11-12 11:02:53 +03:00
Devaev Maxim
0afbf02451 Bump version: 0.39 → 0.40 2018-11-09 22:42:24 +03:00
Devaev Maxim
dd79efd6f5 removed legacy option --every-frame 2018-11-09 22:42:07 +03:00
Devaev Maxim
97ac19a2fe Bump version: 0.38 → 0.39 2018-11-08 04:25:27 +03:00
Devaev Maxim
755e0c2a2a fixed long option for desired fps 2018-11-08 04:25:16 +03:00
Devaev Maxim
ccab33a290 Bump version: 0.37 → 0.38 2018-11-08 03:24:42 +03:00
Devaev Maxim
76a8e65e80 soft_fps -> desired_fps 2018-11-08 03:23:58 +03:00
Devaev Maxim
3b86e64222 more flexible --soft-fps 2018-11-07 21:04:21 +03:00
Devaev Maxim
020482a05a refactoring 2018-11-07 12:11:59 +03:00
Devaev Maxim
1896e22dff unified /stat json with kvmd 2018-11-07 11:27:34 +03:00
Devaev Maxim
56df20fe84 Bump version: 0.36 → 0.37 2018-11-07 05:59:57 +03:00
Devaev Maxim
ed7dabbfcb /ping -> /state; some docs 2018-11-07 05:59:48 +03:00
Devaev Maxim
b1d40d1b3a Bump version: 0.35 → 0.36 2018-11-07 04:22:08 +03:00
Devaev Maxim
43939c7475 combined stream_client cookie 2018-11-07 04:20:57 +03:00
15 changed files with 73 additions and 75 deletions

View File

@@ -1,7 +1,7 @@
[bumpversion]
commit = True
tag = True
current_version = 0.35
current_version = 0.41
parse = (?P<major>\d+)\.(?P<minor>\d+)(\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?)?
serialize =
{major}.{minor}

View File

@@ -3,7 +3,7 @@
pkgname=ustreamer
pkgver=0.35
pkgver=0.41
pkgrel=1
pkgdesc="Lightweight and fast MJPG-HTTP streamer"
url="https://github.com/pi-kvm/ustreamer"

View File

@@ -58,7 +58,7 @@ The recommended way of running µStreamer with [Auvidea B101](https://www.raspbe
$ ./ustreamer \
--format=uyvy \ # Device input format
--encoder=omx \ # Hardware encoding with OpenMAX
--dv-timings \ # use DV-timings
--dv-timings \ # Use DV-timings
--quality=20 \ # OpenMAX has a non-linear quality scale
--drop-same-frames=30 # Save that traffic
```

View File

@@ -21,4 +21,4 @@
#pragma once
#define VERSION "0.35"
#define VERSION "0.41"

View File

@@ -11,7 +11,7 @@
<hr>
<ul>
<li>
<a href="/ping"><b><samp>/ping</samp></b></a><br>
<a href="/state"><b><samp>/state</samp></b></a><br>
Get JSON structure with state of the server.
</li>
<br>
@@ -25,6 +25,12 @@
Get a live stream. Query params:<br>
<br>
<ul>
<li>
<b><samp>key=abc123</samp></b><br>
User-defined key, which is part of cookie <samp>stream_client</samp>, which allows<br>
the stream client to determine its identifier and view statistics using <a href="/state"><samp>/state</samp></a>.
</li>
<br>
<li>
<b><samp>extra_headers=1</samp></b><br>
Add <samp>X-UStreamer-*</samp> headers to /stream handle (like on <a href="/snapshot"><samp>/snapshot</samp></a>).
@@ -40,7 +46,7 @@
<b><samp>dual_final_frames=1</samp></b><br>
Enable workaround for Safari/WebKit bug when using option <samp>--drop-same-frames</samp>.<br>
Without this option, when the frame series is completed, WebKit-based browsers<br>
renders the last one with a delay.
renders the last frame with a delay.
</li>
</ul>
</li>

View File

@@ -38,7 +38,7 @@ const char *HTML_INDEX_PAGE = " \
<hr> \
<ul> \
<li> \
<a href=\"/ping\"><b><samp>/ping</samp></b></a><br> \
<a href=\"/state\"><b><samp>/state</samp></b></a><br> \
Get JSON structure with state of the server. \
</li> \
<br> \
@@ -52,6 +52,12 @@ const char *HTML_INDEX_PAGE = " \
Get a live stream. Query params:<br> \
<br> \
<ul> \
<li> \
<b><samp>key=abc123</samp></b><br> \
User-defined key, which is part of cookie <samp>stream_client</samp>, which allows<br> \
the stream client to determine its identifier and view statistics using <a href=\"/state\"><samp>/state</samp></a>. \
</li> \
<br> \
<li> \
<b><samp>extra_headers=1</samp></b><br> \
Add <samp>X-UStreamer-*</samp> headers to /stream handle (like on <a href=\"/snapshot\"><samp>/snapshot</samp></a>). \
@@ -67,7 +73,7 @@ const char *HTML_INDEX_PAGE = " \
<b><samp>dual_final_frames=1</samp></b><br> \
Enable workaround for Safari/WebKit bug when using option <samp>--drop-same-frames</samp>.<br> \
Without this option, when the frame series is completed, WebKit-based browsers<br> \
renders the last one with a delay. \
renders the last frame with a delay. \
</li> \
</ul> \
</li> \

View File

@@ -84,7 +84,6 @@ struct device_t *device_init() {
dev->standard = V4L2_STD_UNKNOWN;
dev->n_buffers = max_u(sysconf(_SC_NPROCESSORS_ONLN), 1) + 1;
dev->n_workers = dev->n_buffers;
dev->soft_fps = 30;
dev->timeout = 1;
dev->error_delay = 1;
dev->run = run;

View File

@@ -72,8 +72,7 @@ struct device_t {
bool dv_timings;
unsigned n_buffers;
unsigned n_workers;
unsigned soft_fps;
unsigned every_frame;
unsigned desired_fps;
unsigned min_frame_size;
bool persistent;
unsigned timeout;

View File

@@ -129,7 +129,7 @@ void encoder_prepare_live(struct encoder_t *encoder, struct device_t *dev) {
# ifdef OMX_ENCODER
if (encoder->type == ENCODER_TYPE_OMX) {
for (unsigned index = 0; index < encoder->n_omxs; ++index) {
if (omx_encoder_prepare_live(encoder->omxs[index], dev, encoder->quality, encoder->omx_use_ijg) < 0) {
if (omx_encoder_prepare_live(encoder->omxs[index], dev, encoder->quality) < 0) {
goto use_fallback;
}
}
@@ -154,8 +154,6 @@ int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev,
assert(encoder->type != ENCODER_TYPE_UNKNOWN);
dev->run->pictures[buf_index].encode_begin_time = get_now_monotonic();
if (encoder->type == ENCODER_TYPE_CPU) {
jpeg_encoder_compress_buffer(dev, buf_index, encoder->quality);
}
@@ -167,8 +165,6 @@ int encoder_compress_buffer(struct encoder_t *encoder, struct device_t *dev,
}
# endif
dev->run->pictures[buf_index].encode_end_time = get_now_monotonic();
return 0;
# pragma GCC diagnostic ignored "-Wunused-label"

View File

@@ -48,7 +48,6 @@ struct encoder_t {
enum encoder_type_t type;
unsigned quality;
#ifdef OMX_ENCODER
bool omx_use_ijg;
unsigned n_omxs;
struct omx_encoder_t **omxs;
#endif

View File

@@ -51,7 +51,7 @@ static bool _http_get_param_true(struct evkeyvalq *params, const char *key);
static char *_http_get_param_uri(struct evkeyvalq *params, const char *key);
static void _http_callback_root(struct evhttp_request *request, void *arg);
static void _http_callback_ping(struct evhttp_request *request, void *v_server);
static void _http_callback_state(struct evhttp_request *request, void *v_server);
static void _http_callback_snapshot(struct evhttp_request *request, void *v_server);
static void _http_callback_stream(struct evhttp_request *request, void *v_server);
@@ -91,7 +91,7 @@ struct http_server_t *http_server_init(struct stream_t *stream) {
evhttp_set_allowed_methods(run->http, EVHTTP_REQ_GET|EVHTTP_REQ_HEAD);
assert(!evhttp_set_cb(run->http, "/", _http_callback_root, NULL));
assert(!evhttp_set_cb(run->http, "/ping", _http_callback_ping, (void *)server));
assert(!evhttp_set_cb(run->http, "/state", _http_callback_state, (void *)server));
assert(!evhttp_set_cb(run->http, "/snapshot", _http_callback_snapshot, (void *)server));
assert(!evhttp_set_cb(run->http, "/stream", _http_callback_stream, (void *)server));
@@ -118,7 +118,11 @@ int http_server_listen(struct http_server_t *server) {
struct timeval refresh_interval;
refresh_interval.tv_sec = 0;
refresh_interval.tv_usec = 1000000 / (server->run->stream->dev->soft_fps * 2);
if (server->run->stream->dev->desired_fps > 0) {
refresh_interval.tv_usec = 1000000 / (server->run->stream->dev->desired_fps * 2);
} else {
refresh_interval.tv_usec = 16000; // ~60fps
}
assert((server->run->refresh = event_new(server->run->base, -1, EV_PERSIST, _http_exposed_refresh, server)));
assert(!event_add(server->run->refresh, &refresh_interval));
@@ -189,7 +193,7 @@ static void _http_callback_root(struct evhttp_request *request, UNUSED void *arg
evbuffer_free(buf);
}
static void _http_callback_ping(struct evhttp_request *request, void *v_server) {
static void _http_callback_state(struct evhttp_request *request, void *v_server) {
struct http_server_t *server = (struct http_server_t *)v_server;
struct evbuffer *buf;
@@ -197,29 +201,31 @@ static void _http_callback_ping(struct evhttp_request *request, void *v_server)
assert((buf = evbuffer_new()));
assert(evbuffer_add_printf(buf,
"{\"source\": {\"resolution\": {\"width\": %u, \"height\": %u},"
" \"online\": %s, \"quality\": %u, \"soft_fps\": %u, \"captured_fps\": %u},"
" \"stream\": {\"queued_fps\": %u, \"clients\": %u, \"clients_stat\": {",
"{\"ok\": true, \"result\":"
" {\"source\": {\"resolution\": {\"width\": %u, \"height\": %u},"
" \"online\": %s, \"quality\": %u, \"desired_fps\": %u, \"captured_fps\": %u},"
" \"stream\": {\"queued_fps\": %u, \"clients\": %u, \"clients_stat\": {",
(server->fake_width ? server->fake_width : server->run->exposed->width),
(server->fake_height ? server->fake_height : server->run->exposed->height),
bool_to_string(server->run->exposed->online),
server->run->stream->encoder->quality,
server->run->stream->dev->soft_fps,
server->run->stream->dev->desired_fps,
server->run->exposed->captured_fps,
server->run->exposed->queued_fps,
server->run->stream_clients_count
));
for (struct stream_client_t * client = server->run->stream_clients; client != NULL; client = client->next) {
assert(evbuffer_add_printf(buf,
"\"%s\": {\"fps\": %u, \"advance_headers\": %s, \"dual_final_frames\": %s}%s",
"\"%s\": {\"fps\": %u, \"extra_headers\": %s, \"advance_headers\": %s, \"dual_final_frames\": %s}%s",
client->id,
client->fps,
bool_to_string(client->extra_headers),
bool_to_string(client->advance_headers),
bool_to_string(client->dual_final_frames),
(client->next ? ", " : "")
));
}
assert(evbuffer_add_printf(buf, "}}}"));
assert(evbuffer_add_printf(buf, "}}}}"));
ADD_HEADER("Content-Type", "application/json");
evhttp_send_reply(request, HTTP_OK, "OK", buf);
@@ -392,7 +398,7 @@ static void _http_callback_stream_write(struct bufferevent *buf_event, void *v_c
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0" RN
"Pragma: no-cache" RN
"Expires: Mon, 3 Jan 2000 12:34:56 GMT" RN
"Set-Cookie: stream_client_key=%s; stream_client_id=%s; path=/; max-age=30" RN
"Set-Cookie: stream_client=%s/%s; path=/; max-age=30" RN
"Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY RN
RN
"--" BOUNDARY RN,

View File

@@ -40,25 +40,21 @@
#include "http.h"
static const char _short_opts[] = "d:i:x:y:f:a:e:z:tn:w:q:c:s:p:r:h";
static const char _short_opts[] = "d:i:x:y:f:a:z:tn:w:q:c:s:p:r:h";
static const struct option _long_opts[] = {
{"device", required_argument, NULL, 'd'},
{"input", required_argument, NULL, 'i'},
{"width", required_argument, NULL, 'x'},
{"height", required_argument, NULL, 'y'},
{"format", required_argument, NULL, 'f'},
{"format", required_argument, NULL, 'm'},
{"tv-standard", required_argument, NULL, 'a'},
{"soft-fps", required_argument, NULL, 'm'},
{"every-frame", required_argument, NULL, 'e'},
{"desired-fps", required_argument, NULL, 'f'},
{"min-frame-size", required_argument, NULL, 'z'},
{"dv-timings", no_argument, NULL, 't'},
{"buffers", required_argument, NULL, 'b'},
{"workers", required_argument, NULL, 'w'},
{"quality", required_argument, NULL, 'q'},
{"encoder", required_argument, NULL, 'c'},
# ifdef OMX_ENCODER
{"encoder-omx-use-ijg", required_argument, NULL, 500},
# endif
{"device-timeout", required_argument, NULL, 1000},
{"device-persistent", no_argument, NULL, 1001},
{"device-error-delay", required_argument, NULL, 1002},
@@ -102,12 +98,11 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf(" -i|--input <N> -- Input channel. Default: %u.\n\n", dev->input);
printf(" -x|--width <N> -- Initial image width. Default: %d.\n\n", dev->width);
printf(" -y|--height <N> -- Initial image height. Default: %d.\n\n", dev->height);
printf(" -f|--format <fmt> -- Image format.\n");
printf(" -m|--format <fmt> -- Image format.\n");
printf(" Available: %s; default: YUYV.\n\n", FORMATS_STR);
printf(" -a|--tv-standard <std> -- Force TV standard.\n");
printf(" Available: %s; default: disabled.\n\n", STANDARDS_STR);
printf(" -m|--soft-fps <N> -- Soft FPS limit; default: %u.\n\n", dev->soft_fps);
printf(" -e|--every-frame <N> -- Drop all input frames except specified. Default: disabled.\n\n");
printf(" -f|--desired-fps <N> -- Desired FPS; default: maximum as possible.\n\n");
printf(" -z|--min-frame-size <N> -- Drop frames smaller then this limit.\n");
printf(" Useful if the device produces small-sized garbage frames.\n\n");
printf(" -t|--dv-timings -- Enable DV timings queriyng and events processing.\n");
@@ -119,10 +114,6 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf(" -q|--quality <N> -- Set quality of JPEG encoding from 1 to 100 (best). Default: %d.\n\n", encoder->quality);
printf(" --encoder <type> -- Use specified encoder. It may affects to workers number.\n");
printf(" -- Available: %s; default: CPU.\n\n", ENCODER_TYPES_STR);
# ifdef OMX_ENCODER
printf(" --encoder-omx-use-ijg -- Use the standard IJG quality tables when encoding images using OMX.\n");
printf(" Default: disabled.\n\n");
# endif
printf(" --device-timeout <seconds> -- Timeout for device querying. Default: %d\n\n", dev->timeout);
printf(" --device-persistent -- Don't re-initialize device on timeout. Default: disabled.\n\n");
printf(" --device-error-delay <seconds> -- Delay before trying to connect to the device again\n");
@@ -135,8 +126,8 @@ static void _help(struct device_t *dev, struct encoder_t *encoder, struct http_s
printf(" It can significantly reduce the outgoing traffic, but will increase\n");
printf(" the CPU loading. Don't use this option with analog signal sources\n");
printf(" or webcams, it's useless. Default: disabled.\n\n");
printf(" --fake-width <N> -- Override image width for /ping. Default: disabled\n\n");
printf(" --fake-height <N> -- Override image height for /ping. Default: disabled.\n\n");
printf(" --fake-width <N> -- Override image width for /state. Default: disabled\n\n");
printf(" --fake-height <N> -- Override image height for /state. Default: disabled.\n\n");
printf(" --server-timeout <seconds> -- Timeout for client connections. Default: %d\n\n", server->timeout);
printf("Misc options:\n");
printf("-------------\n");
@@ -177,20 +168,16 @@ static int _parse_options(int argc, char *argv[], struct device_t *dev, struct e
case 'y': OPT_UNSIGNED(dev->height, "--height", 180, 1200);
# pragma GCC diagnostic ignored "-Wsign-compare"
# pragma GCC diagnostic push
case 'f': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format");
case 'm': OPT_PARSE(dev->format, device_parse_format, FORMAT_UNKNOWN, "pixel format");
# pragma GCC diagnostic pop
case 'a': OPT_PARSE(dev->standard, device_parse_standard, STANDARD_UNKNOWN, "TV standard");
case 'm': OPT_UNSIGNED(dev->soft_fps, "--soft-fps", 1, 30);
case 'e': OPT_UNSIGNED(dev->every_frame, "--every-frame", 1, 30);
case 'f': OPT_UNSIGNED(dev->desired_fps, "--desired-fps", 0, 30);
case 'z': OPT_UNSIGNED(dev->min_frame_size, "--min-frame-size", 0, 8192);
case 't': OPT_SET(dev->dv_timings, true);
case 'b': OPT_UNSIGNED(dev->n_buffers, "--buffers", 1, 32);
case 'w': OPT_UNSIGNED(dev->n_workers, "--workers", 1, 32);
case 'q': OPT_UNSIGNED(encoder->quality, "--quality", 1, 100);
case 'c': OPT_PARSE(encoder->type, encoder_parse_type, ENCODER_TYPE_UNKNOWN, "encoder type");
# ifdef OMX_ENCODER
case 500: OPT_SET(encoder->omx_use_ijg, true);
# endif
case 1000: OPT_UNSIGNED(dev->timeout, "--device-timeout", 1, 60);
case 1001: OPT_SET(dev->persistent, true);
case 1002: OPT_UNSIGNED(dev->error_delay, "--device-error-delay", 1, 60);

View File

@@ -51,7 +51,7 @@ static int _i_omx = 0;
static int _omx_init_component(struct omx_encoder_t *omx);
static int _omx_init_disable_ports(struct omx_encoder_t *omx);
static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev);
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality, const bool use_ijg);
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality);
static int _omx_encoder_clear_ports(struct omx_encoder_t *omx);
static OMX_ERRORTYPE _omx_event_handler(UNUSED OMX_HANDLETYPE encoder,
@@ -148,7 +148,7 @@ void omx_encoder_destroy(struct omx_encoder_t *omx) {
free(omx);
}
int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality, const bool use_ijg) {
int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality) {
if (component_set_state(&omx->encoder, OMX_StateIdle) < 0) {
return -1;
}
@@ -158,7 +158,7 @@ int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, co
if (_omx_setup_input(omx, dev) < 0) {
return -1;
}
if (_omx_setup_output(omx, quality, use_ijg) < 0) {
if (_omx_setup_output(omx, quality) < 0) {
return -1;
}
if (component_set_state(&omx->encoder, OMX_StateExecuting) < 0) {
@@ -329,7 +329,7 @@ static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev) {
return 0;
}
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality, const bool use_ijg) {
static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality) {
OMX_ERRORTYPE error;
OMX_PARAM_PORTDEFINITIONTYPE portdef;
@@ -365,7 +365,7 @@ static int _omx_setup_output(struct omx_encoder_t *omx, const unsigned quality,
}
}
if (use_ijg) {
{
OMX_PARAM_IJGSCALINGTYPE ijg;
OMX_INIT_STRUCTURE(ijg);

View File

@@ -51,5 +51,5 @@ struct omx_encoder_t {
struct omx_encoder_t *omx_encoder_init();
void omx_encoder_destroy(struct omx_encoder_t *omx);
int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality, const bool use_ijg);
int omx_encoder_prepare_live(struct omx_encoder_t *omx, struct device_t *dev, const unsigned quality);
int omx_encoder_compress_buffer(struct omx_encoder_t *omx, struct device_t *dev, const unsigned index);

View File

@@ -78,11 +78,11 @@ void stream_loop(struct stream_t *stream) {
pool.workers_stop = &workers_stop;
LOG_INFO("Using V4L2 device: %s", stream->dev->path);
LOG_INFO("Using desired FPS: %u", stream->dev->desired_fps);
while (_stream_init_loop(stream->dev, &pool) == 0) {
struct worker_t *oldest_worker = NULL;
struct worker_t *last_worker = NULL;
unsigned frames_count = 0;
long double grab_after = 0;
unsigned fluency_passed = 0;
unsigned captured_fps_accum = 0;
@@ -183,15 +183,6 @@ void stream_loop(struct stream_t *stream) {
}
stream->dev->run->pictures[buf_info.index].grab_time = now;
if (stream->dev->every_frame) {
if (frames_count < stream->dev->every_frame - 1) {
frames_count += 1;
LOG_DEBUG("Dropping frame %d for option --every-frame=%d", frames_count, stream->dev->every_frame);
goto pass_frame;
}
frames_count = 0;
}
// Workaround for broken, corrupted frames:
// Under low light conditions corrupted frames may get captured.
// The good thing is such frames are quite small compared to the regular pictures.
@@ -321,25 +312,28 @@ static void _stream_expose_picture(struct stream_t *stream, unsigned buf_index)
}
static long double _stream_get_fluency_delay(struct device_t *dev, struct workers_pool_t *pool) {
long double comp_time = 0;
long double sum_comp_time = 0;
long double avg_comp_time;
long double min_delay;
long double soft_delay;
for (unsigned number = 0; number < dev->n_workers; ++number) {
A_PTHREAD_M_LOCK(&pool->workers[number].last_comp_time_mutex);
if (pool->workers[number].last_comp_time > 0) {
comp_time += pool->workers[number].last_comp_time;
sum_comp_time += pool->workers[number].last_comp_time;
}
A_PTHREAD_M_UNLOCK(&pool->workers[number].last_comp_time_mutex);
}
comp_time = comp_time / dev->n_workers; // Среднее время работы воркеров
avg_comp_time = sum_comp_time / dev->n_workers; // Среднее время работы воркеров
min_delay = comp_time / dev->n_workers; // Минимальное время работы размазывается на N воркеров
soft_delay = ((long double)1) / dev->soft_fps; // Искусственное время задержки на основе желаемого FPS
min_delay = avg_comp_time / dev->n_workers; // Среднее время работы размазывается на N воркеров
if (min_delay > 0) {
if (dev->desired_fps > 0 && min_delay > 0) {
// Искусственное время задержки на основе желаемого FPS, если включен --desired-fps
soft_delay = ((long double) 1) / dev->desired_fps - sum_comp_time;
return (min_delay > soft_delay ? min_delay : soft_delay);
}
return min_delay;
}
@@ -437,18 +431,22 @@ static void *_stream_worker_thread(void *v_ctx) {
A_PTHREAD_C_WAIT_TRUE(*ctx->has_job, ctx->has_job_cond, ctx->has_job_mutex);
A_PTHREAD_M_UNLOCK(ctx->has_job_mutex);
# define PICTURE(_next) ctx->dev->run->pictures[ctx->buf_index]._next
if (!*ctx->workers_stop) {
LOG_DEBUG("Worker %u compressing JPEG from buffer %d ...", ctx->number, ctx->buf_index);
PICTURE(encode_begin_time) = get_now_monotonic();
if (encoder_compress_buffer(ctx->encoder, ctx->dev, ctx->number, ctx->buf_index) < 0) {
*ctx->job_failed = true;
}
PICTURE(encode_end_time) = get_now_monotonic();
if (_stream_release_buffer(ctx->dev, &ctx->buf_info) == 0) {
*ctx->job_start_time = ctx->dev->run->pictures[ctx->buf_index].encode_begin_time;
*ctx->job_start_time = PICTURE(encode_begin_time);
*ctx->has_job = false;
long double last_comp_time = ctx->dev->run->pictures[ctx->buf_index].encode_end_time - *ctx->job_start_time;
long double last_comp_time = PICTURE(encode_end_time) - *ctx->job_start_time;
A_PTHREAD_M_LOCK(ctx->last_comp_time_mutex);
*ctx->last_comp_time = last_comp_time;
@@ -456,7 +454,7 @@ static void *_stream_worker_thread(void *v_ctx) {
LOG_VERBOSE(
"Compressed JPEG size=%ld; time=%0.3Lf; worker=%u; buffer=%d",
ctx->dev->run->pictures[ctx->buf_index].size, last_comp_time, ctx->number, ctx->buf_index
PICTURE(size), last_comp_time, ctx->number, ctx->buf_index
);
} else {
*ctx->job_failed = true;
@@ -464,6 +462,8 @@ static void *_stream_worker_thread(void *v_ctx) {
}
}
# undef PICTURE
A_PTHREAD_M_LOCK(ctx->free_workers_mutex);
*ctx->free_workers += 1;
A_PTHREAD_M_UNLOCK(ctx->free_workers_mutex);