refactoring

This commit is contained in:
Devaev Maxim 2020-12-09 18:44:12 +03:00
parent 9039aa8ac5
commit f19ab11f76
18 changed files with 151 additions and 167 deletions

View File

@ -24,7 +24,7 @@ _PROG_SRCS = $(shell ls \
src/common/*.c \
src/ustreamer/*.c \
src/ustreamer/http/*.c \
src/ustreamer/http/data/*.c \
src/ustreamer/data/*.c \
src/ustreamer/encoders/cpu/*.c \
src/ustreamer/encoders/hw/*.c \
)
@ -90,8 +90,8 @@ uninstall:
regen:
tools/make-jpeg-h.py src/ustreamer/http/data/blank.jpeg src/ustreamer/http/data/blank_jpeg.c BLANK
tools/make-html-h.py src/ustreamer/http/data/index.html src/ustreamer/http/data/index_html.c INDEX
tools/make-jpeg-h.py src/ustreamer/data/blank.jpeg src/ustreamer/data/blank_jpeg.c BLANK
tools/make-html-h.py src/ustreamer/data/index.html src/ustreamer/data/index_html.c INDEX
$(PROG): $(_PROG_SRCS:%.c=$(BUILD)/%.o)

View File

@ -36,7 +36,7 @@ static int _jpeg_read_geometry(FILE *fp, unsigned *width, unsigned *height);
static void _jpeg_error_handler(j_common_ptr jpeg);
struct frame_t *blank_picture_init(const char *path) {
struct frame_t *blank_frame_init(const char *path) {
struct frame_t *blank = NULL;
if (path) {
@ -55,7 +55,7 @@ struct frame_t *blank_picture_init(const char *path) {
static struct frame_t *_init_internal(void) {
struct frame_t *blank;
blank = frame_init();
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;
@ -66,7 +66,7 @@ static struct frame_t *_init_external(const char *path) {
FILE *fp = NULL;
struct frame_t *blank;
blank = frame_init();
blank = frame_init("blank_external");
if ((fp = fopen(path, "rb")) == NULL) {
LOG_PERROR("Can't open blank placeholder '%s'", path);

View File

@ -28,11 +28,11 @@
#include <jpeglib.h>
#include "../../common/tools.h"
#include "../../common/logging.h"
#include "../frame.h"
#include "../common/tools.h"
#include "../common/logging.h"
#include "frame.h"
#include "data/blank_jpeg.h"
struct frame_t *blank_picture_init(const char *path);
struct frame_t *blank_frame_init(const char *path);

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -24,7 +24,7 @@
#include <sys/types.h>
#include "../../../common/config.h"
#include "../../common/config.h"
extern const char *const HTML_INDEX_PAGE;

View File

@ -322,7 +322,7 @@ static int _omx_setup_input(struct omx_encoder_t *omx, struct device_t *dev) {
portdef.format.image.nSliceHeight = align_size(dev->run->height, 16);
portdef.format.image.bFlagErrorConcealment = OMX_FALSE;
portdef.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
portdef.nBufferSize = frame_get_generous_size(dev->run->width, dev->run->height);
portdef.nBufferSize = ((dev->run->width * dev->run->height) << 1) * 2;
# define MAP_FORMAT(_v4l2_format, _omx_format) \
case _v4l2_format: { portdef.format.image.eColorFormat = _omx_format; break; }

View File

@ -23,10 +23,12 @@
#include "frame.h"
struct frame_t *frame_init(void) {
struct frame_t *frame_init(const char *role) {
struct frame_t *frame;
A_CALLOC(frame, 1);
frame->role = role;
frame_realloc_data(frame, 500 * 1024);
return frame;
}
@ -37,14 +39,10 @@ void frame_destroy(struct frame_t *frame) {
free(frame);
}
size_t frame_get_generous_size(unsigned width, unsigned height) {
return ((width * height) << 1) * 2;
}
void frame_realloc_data(struct frame_t *frame, size_t size) {
if (frame->allocated < size) {
LOG_DEBUG("Increasing frame %p buffer: %zu -> %zu (+%zu)",
frame, frame->allocated, size, size - frame->allocated);
LOG_DEBUG("Increasing frame buffer '%s': %zu -> %zu (+%zu)",
frame->role, frame->allocated, size, size - frame->allocated);
A_REALLOC(frame->data, size);
frame->allocated = size;
}
@ -69,6 +67,7 @@ void frame_copy(const struct frame_t *src, struct frame_t *dest) {
# define COPY(_field) dest->_field = src->_field
// Don't copy the role
COPY(used);
COPY(width);

View File

@ -33,6 +33,7 @@
struct frame_t {
const char *role;
unsigned char *data;
size_t used;
size_t allocated;
@ -44,11 +45,9 @@ struct frame_t {
};
struct frame_t *frame_init(void);
struct frame_t *frame_init(const char *role);
void frame_destroy(struct frame_t *frame);
size_t frame_get_generous_size(unsigned width, unsigned height);
void frame_realloc_data(struct frame_t *frame, size_t size);
void frame_set_data(struct frame_t *frame, const unsigned char *data, size_t size);
void frame_append_data(struct frame_t *frame, const unsigned char *data, size_t size);

View File

@ -37,8 +37,7 @@ static void _http_callback_stream_error(struct bufferevent *buf_event, short wha
static void _http_exposed_refresh(int fd, short event, void *v_server);
static void _http_queue_send_stream(struct http_server_t *server, bool stream_updated, bool frame_updated);
static bool _expose_new_picture_unsafe(struct http_server_t *server);
static bool _expose_blank_picture(struct http_server_t *server);
static bool _expose_new_frame(struct http_server_t *server);
static void _format_bufferevent_reason(short what, char *reason);
@ -54,12 +53,11 @@ struct http_server_t *http_server_init(struct stream_t *stream) {
struct exposed_t *exposed;
A_CALLOC(exposed, 1);
exposed->frame = frame_init();
exposed->frame = frame_init("http_exposed");
A_CALLOC(run, 1);
run->stream = stream;
run->exposed = exposed;
run->drop_same_frames_blank = 10;
A_CALLOC(server, 1);
server->host = "127.0.0.1";
@ -70,7 +68,6 @@ struct http_server_t *http_server_init(struct stream_t *stream) {
server->static_path = "";
server->allow_origin = "";
server->timeout = 10;
server->last_as_blank = -1;
server->run = run;
assert(!evthread_use_pthreads());
@ -108,10 +105,6 @@ void http_server_destroy(struct http_server_t *server) {
free(RUN(auth_token));
}
if (RUN(blank)) {
frame_destroy(RUN(blank));
}
frame_destroy(EX(frame));
free(RUN(exposed));
free(server->run);
@ -131,15 +124,10 @@ int http_server_listen(struct http_server_t *server) {
assert(!evhttp_set_cb(RUN(http), "/stream", _http_callback_stream, (void *)server));
}
RUN(drop_same_frames_blank) = max_u(server->drop_same_frames, RUN(drop_same_frames_blank));
RUN(blank) = blank_picture_init(server->blank_path);
// See _expose_blank_picture()
frame_copy(RUN(blank), EX(frame));
EX(expose_begin_ts) = get_now_monotonic();
EX(expose_cmp_ts) = EX(expose_begin_ts);
EX(expose_end_ts) = EX(expose_begin_ts);
// See _http_exposed_refresh()
frame_copy(STREAM(blank), EX(frame));
EX(expose_begin_ts) = 0;
EX(expose_cmp_ts) = 0;
EX(expose_end_ts) = 0;
EX(notify_last_width) = EX(frame->width);
EX(notify_last_height) = EX(frame->height);
@ -755,30 +743,18 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
bool stream_updated = false;
bool frame_updated = false;
# define UNLOCK_STREAM { \
atomic_store(&STREAM(video->updated), false); \
A_MUTEX_UNLOCK(&STREAM(video->mutex)); \
}
if (atomic_load(&STREAM(video->updated))) {
LOG_DEBUG("Refreshing HTTP exposed ...");
A_MUTEX_LOCK(&STREAM(video->mutex));
if (STREAM(video->online)) {
frame_updated = _expose_new_picture_unsafe(server);
UNLOCK_STREAM;
} else {
UNLOCK_STREAM;
frame_updated = _expose_blank_picture(server);
}
frame_updated = _expose_new_frame(server);
stream_updated = true;
} else if (!EX(online)) {
LOG_DEBUG("Refreshing HTTP exposed (BLANK) ...");
frame_updated = _expose_blank_picture(server);
} else if (EX(expose_end_ts) + 1 < get_now_monotonic()) {
LOG_DEBUG("HTTP: Repeating exposed ...");
EX(expose_begin_ts) = get_now_monotonic();
EX(expose_cmp_ts) = EX(expose_begin_ts);
EX(expose_end_ts) = EX(expose_begin_ts);
frame_updated = true;
stream_updated = true;
}
# undef UNLOCK_STREAM
_http_queue_send_stream(server, stream_updated, frame_updated);
if (
@ -797,87 +773,51 @@ static void _http_exposed_refresh(UNUSED int fd, UNUSED short what, void *v_serv
}
}
static bool _expose_new_picture_unsafe(struct http_server_t *server) {
static bool _expose_new_frame(struct http_server_t *server) {
bool updated = false;
A_MUTEX_LOCK(&STREAM(video->mutex));
LOG_DEBUG("HTTP: Updating exposed frame (online=%d) ...", STREAM(video->online));
EX(captured_fps) = STREAM(video->captured_fps);
EX(expose_begin_ts) = get_now_monotonic();
if (server->drop_same_frames) {
if (server->drop_same_frames && STREAM(video->online)) {
bool need_drop = false;
bool maybe_same = false;
if (
EX(online)
&& EX(dropped) < server->drop_same_frames
&& frame_compare(EX(frame), STREAM(video->frame))
(need_drop = (EX(dropped) < server->drop_same_frames))
&& (maybe_same = frame_compare(EX(frame), STREAM(video->frame)))
) {
EX(expose_cmp_ts) = get_now_monotonic();
EX(expose_end_ts) = EX(expose_cmp_ts);
LOG_VERBOSE("HTTP: Dropped same frame number %u; cmp_time=%.06Lf",
EX(dropped), EX(expose_cmp_ts) - EX(expose_begin_ts));
EX(dropped) += 1;
return false; // Not updated
goto not_updated;
} else {
EX(expose_cmp_ts) = get_now_monotonic();
LOG_VERBOSE("HTTP: Passed same frame check (frames are differ); cmp_time=%.06Lf",
EX(expose_cmp_ts) - EX(expose_begin_ts));
LOG_VERBOSE("HTTP: Passed same frame check (need_drop=%d, maybe_same=%d); cmp_time=%.06Lf",
need_drop, maybe_same, (EX(expose_cmp_ts) - EX(expose_begin_ts)));
}
}
frame_copy(STREAM(video->frame), EX(frame));
EX(online) = true;
EX(online) = STREAM(video->online);
EX(dropped) = 0;
EX(expose_cmp_ts) = EX(expose_begin_ts);
EX(expose_end_ts) = get_now_monotonic();
LOG_VERBOSE("HTTP: Exposed new frame; full exposition time = %.06Lf",
EX(expose_end_ts) - EX(expose_begin_ts));
LOG_VERBOSE("HTTP: Exposed frame: online=%d, exp_time=%.06Lf",
EX(online), EX(expose_end_ts) - EX(expose_begin_ts));
return true; // Updated
}
static bool _expose_blank_picture(struct http_server_t *server) {
EX(expose_begin_ts) = get_now_monotonic();
EX(expose_cmp_ts) = EX(expose_begin_ts);
# define EXPOSE_BLANK frame_copy(RUN(blank), EX(frame))
if (EX(online)) { // Если переходим из online в offline
if (server->last_as_blank < 0) { // Если last_as_blank выключено, просто покажем картинку
LOG_INFO("HTTP: Changed frame to BLANK");
EXPOSE_BLANK;
} else if (server->last_as_blank > 0) { // Если нужен таймер - запустим
LOG_INFO("HTTP: Freezing last alive frame for %d seconds", server->last_as_blank);
EX(last_as_blank_ts) = get_now_monotonic();
} else { // last_as_blank == 0 - показываем последний фрейм вечно
LOG_INFO("HTTP: Freezing last alive frame forever");
}
goto updated;
}
if ( // Если уже оффлайн, включена фича last_as_blank с таймером и он запущен
server->last_as_blank > 0
&& EX(last_as_blank_ts) > 0
&& EX(last_as_blank_ts) + server->last_as_blank < EX(expose_begin_ts)
) {
LOG_INFO("HTTP: Changed last alive frame to BLANK");
EXPOSE_BLANK;
EX(last_as_blank_ts) = 0; // Останавливаем таймер
goto updated;
}
# undef EXPOSE_BLANK
if (EX(dropped) < RUN(drop_same_frames_blank)) {
LOG_PERF("HTTP: Dropped same frame (BLANK) number %u", EX(dropped));
EX(dropped) += 1;
EX(expose_end_ts) = get_now_monotonic();
return false; // Not updated
}
updated:
EX(captured_fps) = 0;
EX(online) = false;
EX(dropped) = 0;
EX(expose_end_ts) = get_now_monotonic();
return true; // Updated
updated = true;
not_updated:
atomic_store(&STREAM(video->updated), false);
A_MUTEX_UNLOCK(&STREAM(video->mutex));
return updated;
}
static void _format_bufferevent_reason(short what, char *reason) {

View File

@ -56,6 +56,7 @@
#include "../../common/threading.h"
#include "../../common/logging.h"
#include "../../common/process.h"
#include "../data/index_html.h"
#include "../frame.h"
#include "../encoder.h"
#include "../stream.h"
@ -68,9 +69,6 @@
#include "base64.h"
#include "mime.h"
#include "static.h"
#include "blank.h"
#include "data/index_html.h"
struct stream_client_t {
@ -96,14 +94,13 @@ struct stream_client_t {
struct exposed_t {
struct frame_t *frame;
unsigned captured_fps;
unsigned queued_fps;
bool online;
unsigned dropped;
long double expose_begin_ts;
long double expose_cmp_ts;
long double expose_end_ts;
long double last_as_blank_ts;
unsigned captured_fps;
unsigned queued_fps;
bool online;
unsigned dropped;
long double expose_begin_ts;
long double expose_cmp_ts;
long double expose_end_ts;
bool notify_last_online;
unsigned notify_last_width;
@ -120,8 +117,6 @@ struct http_server_runtime_t {
struct exposed_t *exposed;
struct stream_client_t *stream_clients;
unsigned stream_clients_count;
struct frame_t *blank;
unsigned drop_same_frames_blank;
};
struct http_server_t {
@ -138,8 +133,6 @@ struct http_server_t {
char *static_path;
char *allow_origin;
char *blank_path;
int last_as_blank;
unsigned drop_same_frames;
bool slowdown;
unsigned fake_width;

View File

@ -132,6 +132,8 @@ static const struct option _LONG_OPTS[] = {
# ifdef WITH_OMX
{"glitched-resolutions", required_argument, NULL, _O_GLITCHED_RESOLUTIONS},
# endif
{"blank", required_argument, NULL, _O_BLANK},
{"last-as-blank", required_argument, NULL, _O_LAST_AS_BLANK},
{"device-timeout", required_argument, NULL, _O_DEVICE_TIMEOUT},
{"device-error-delay", required_argument, NULL, _O_DEVICE_ERROR_DELAY},
@ -157,8 +159,6 @@ static const struct option _LONG_OPTS[] = {
{"user", required_argument, NULL, _O_USER},
{"passwd", required_argument, NULL, _O_PASSWD},
{"static", required_argument, NULL, _O_STATIC},
{"blank", required_argument, NULL, _O_BLANK},
{"last-as-blank", required_argument, NULL, _O_LAST_AS_BLANK},
{"drop-same-frames", required_argument, NULL, _O_DROP_SAME_FRAMES},
{"slowdown", no_argument, NULL, _O_SLOWDOWN},
{"allow-origin", required_argument, NULL, _O_ALLOW_ORIGIN},
@ -231,6 +231,9 @@ struct options_t *options_init(int argc, char *argv[]) {
}
void options_destroy(struct options_t *options) {
if (options->blank) {
frame_destroy(options->blank);
}
for (int index = 0; index < options->argc; ++index) {
free(options->argv_copy[index]);
}
@ -313,6 +316,7 @@ int options_parse(
int short_index;
int opt_index;
char short_opts[1024] = {0};
char *blank_path = NULL;
# ifdef WITH_SETPROCTITLE
char *process_name_prefix = NULL;
# endif
@ -354,6 +358,8 @@ int options_parse(
}
break;
# endif
case _O_BLANK: OPT_SET(blank_path, optarg);
case _O_LAST_AS_BLANK: OPT_NUMBER("--last-as-blank", stream->last_as_blank, 0, 86400, 0);
case _O_DEVICE_TIMEOUT: OPT_NUMBER("--device-timeout", dev->timeout, 1, 60, 0);
case _O_DEVICE_ERROR_DELAY: OPT_NUMBER("--device-error-delay", stream->error_delay, 1, 60, 0);
@ -392,8 +398,6 @@ int options_parse(
case _O_USER: OPT_SET(server->user, optarg);
case _O_PASSWD: OPT_SET(server->passwd, optarg);
case _O_STATIC: OPT_SET(server->static_path, optarg);
case _O_BLANK: OPT_SET(server->blank_path, optarg);
case _O_LAST_AS_BLANK: OPT_NUMBER("--last-as-blank", server->last_as_blank, 0, 86400, 0);
case _O_DROP_SAME_FRAMES: OPT_NUMBER("--drop-same-frames", server->drop_same_frames, 0, VIDEO_MAX_FPS, 0);
case _O_SLOWDOWN: OPT_SET(server->slowdown, true);
case _O_FAKE_RESOLUTION: OPT_RESOLUTION("--fake-resolution", server->fake_width, server->fake_height, false);
@ -443,6 +447,9 @@ int options_parse(
}
}
options->blank = blank_frame_init(blank_path);
stream->blank = options->blank;
# ifdef WITH_SETPROCTITLE
if (process_name_prefix != NULL) {
process_set_name_prefix(options->argc, options->argv, process_name_prefix);
@ -618,6 +625,12 @@ static void _help(
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");
# endif
printf(" -k|--blank <path> ─────────────────── Path to JPEG file that will be shown when the device is disconnected\n");
printf(" during the streaming. Default: black screen 640x480 with 'NO SIGNAL'.\n\n");
printf(" -K|--last-as-blank <sec> ──────────── Show the last frame received from the camera after it was disconnected,\n");
printf(" but no more than specified time (or endlessly if 0 is specified).\n");
printf(" If the device has not yet been online, display 'NO SIGNAL' or the image\n");
printf(" specified by option --blank. Default: disabled.\n\n");
printf(" --device-timeout <sec> ────────────── Timeout for device querying. Default: %u.\n\n", dev->timeout);
printf(" --device-error-delay <sec> ────────── Delay before trying to connect to the device again\n");
printf(" after an error (timeout for example). Default: %u.\n\n", stream->error_delay);
@ -648,12 +661,6 @@ static void _help(
printf(" --passwd <str> ───────────── HTTP basic auth passwd. Default: empty.\n\n");
printf(" --static <path> ───────────── Path to dir with static files instead of embedded root index page.\n");
printf(" Symlinks are not supported for security reasons. Default: disabled.\n\n");
printf(" -k|--blank <path> ────────── Path to JPEG file that will be shown when the device is disconnected\n");
printf(" during the streaming. Default: black screen 640x480 with 'NO SIGNAL'.\n\n");
printf(" -K|--last-as-blank <sec> ─── Show the last frame received from the camera after it was disconnected,\n");
printf(" but no more than specified time (or endlessly if 0 is specified).\n");
printf(" If the device has not yet been online, display 'NO SIGNAL' or the image\n");
printf(" specified by option --blank. Default: disabled.\n\n");
printf(" -e|--drop-same-frames <N> ── Don't send identical frames to clients, but no more than specified number.\n");
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");

View File

@ -38,7 +38,9 @@
#include "../common/process.h"
#include "device.h"
#include "frame.h"
#include "encoder.h"
#include "blank.h"
#include "stream.h"
#include "http/server.h"
#ifdef WITH_GPIO
@ -47,9 +49,10 @@
struct options_t {
int argc;
char **argv;
char **argv_copy;
int argc;
char **argv;
char **argv_copy;
struct frame_t *blank;
};

View File

@ -30,6 +30,7 @@ struct _worker_t {
atomic_bool *workers_stop;
long double last_comp_time;
char *frame_role;
struct frame_t *frame;
pthread_mutex_t has_job_mutex;
@ -70,7 +71,7 @@ struct _workers_pool_t {
static struct _workers_pool_t *_stream_init_loop(struct stream_t *stream);
static struct _workers_pool_t *_stream_init_one(struct stream_t *stream);
static void _stream_expose_picture(struct stream_t *stream, struct frame_t *frame, unsigned captured_fps);
static void _stream_expose_frame(struct stream_t *stream, struct frame_t *frame, unsigned captured_fps);
static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream);
static void _workers_pool_destroy(struct _workers_pool_t *pool);
@ -92,11 +93,12 @@ struct stream_t *stream_init(struct device_t *dev, struct encoder_t *encoder) {
atomic_init(&proc->slowdown, false);
A_CALLOC(video, 1);
video->frame = frame_init();
video->frame = frame_init("stream_video");
atomic_init(&video->updated, false);
A_MUTEX_INIT(&video->mutex);
A_CALLOC(stream, 1);
stream->last_as_blank = -1;
stream->error_delay = 1;
# ifdef WITH_RAWSINK
stream->rawsink_name = "";
@ -140,9 +142,6 @@ void stream_loop(struct stream_t *stream) {
LOG_INFO("Capturing ...");
LOG_DEBUG("Pre-allocating memory for stream frame ...");
frame_realloc_data(stream->video->frame, frame_get_generous_size(DEV(run->width), DEV(run->height)));
while (!atomic_load(&stream->proc->stop)) {
struct _worker_t *ready_wr;
@ -153,7 +152,7 @@ void stream_loop(struct stream_t *stream) {
if (!ready_wr->job_failed) {
if (ready_wr->job_timely) {
_stream_expose_picture(stream, ready_wr->frame, captured_fps);
_stream_expose_frame(stream, ready_wr->frame, captured_fps);
LOG_PERF("##### Encoded frame exposed; worker=%u", ready_wr->number);
} else {
LOG_PERF("----- Encoded frame dropped; worker=%u", ready_wr->number);
@ -255,11 +254,6 @@ void stream_loop(struct stream_t *stream) {
}
}
A_MUTEX_LOCK(&stream->video->mutex);
stream->video->online = false;
atomic_store(&stream->video->updated, true);
A_MUTEX_UNLOCK(&stream->video->mutex);
_workers_pool_destroy(pool);
device_switch_capturing(stream->dev, false);
device_close(stream->dev);
@ -293,6 +287,8 @@ static struct _workers_pool_t *_stream_init_loop(struct stream_t *stream) {
LOG_DEBUG("%s: stream->proc->stop=%d", __FUNCTION__, atomic_load(&stream->proc->stop));
while (!atomic_load(&stream->proc->stop)) {
_stream_expose_frame(stream, NULL, 0);
if (access(stream->dev->path, R_OK|W_OK) < 0) {
if (access_error != errno) {
SEP_INFO('=');
@ -333,16 +329,57 @@ static struct _workers_pool_t *_stream_init_one(struct stream_t *stream) {
return NULL;
}
static void _stream_expose_picture(struct stream_t *stream, struct frame_t *frame, unsigned captured_fps) {
A_MUTEX_LOCK(&stream->video->mutex);
static void _stream_expose_frame(struct stream_t *stream, struct frame_t *frame, unsigned captured_fps) {
# define VID(_next) stream->video->_next
frame_copy(frame, stream->video->frame);
struct frame_t *new = NULL;
stream->video->online = true;
stream->video->captured_fps = captured_fps;
atomic_store(&stream->video->updated, true);
A_MUTEX_LOCK(&VID(mutex));
A_MUTEX_UNLOCK(&stream->video->mutex);
if (frame) {
new = frame;
VID(last_as_blank_ts) = 0; // Останавливаем таймер
LOG_DEBUG("Exposed ALIVE video frame");
} else {
if (VID(online)) { // Если переходим из online в offline
if (stream->last_as_blank < 0) { // Если last_as_blank выключен, просто покажем старую картинку
new = stream->blank;
LOG_INFO("Changed video frame to BLANK");
} else if (stream->last_as_blank > 0) { // // Если нужен таймер - запустим
VID(last_as_blank_ts) = get_now_monotonic() + stream->last_as_blank;
LOG_INFO("Freezed last ALIVE video frame for %d seconds", stream->last_as_blank);
} else { // last_as_blank == 0 - показываем последний фрейм вечно
LOG_INFO("Freezed last ALIVE video frame forever");
}
} else if (stream->last_as_blank < 0) {
new = stream->blank;
LOG_INFO("Changed video frame to BLANK");
}
if ( // Если уже оффлайн, включена фича last_as_blank с таймером и он запущен
stream->last_as_blank > 0
&& VID(last_as_blank_ts) != 0
&& VID(last_as_blank_ts) < get_now_monotonic()
) {
new = stream->blank;
VID(last_as_blank_ts) = 0; // // Останавливаем таймер
LOG_INFO("Changed last ALIVE video frame to BLANK");
}
}
if (new) {
frame_copy(new, VID(frame));
} else if (VID(frame->used) == 0) { // Инициализация
frame_copy(stream->blank, VID(frame));
frame = NULL;
}
VID(online) = frame;
VID(captured_fps) = captured_fps;
atomic_store(&VID(updated), true);
A_MUTEX_UNLOCK(&VID(mutex));
# undef VID
}
static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream) {
@ -350,7 +387,6 @@ static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream) {
# define RUN(_next) stream->dev->run->_next
struct _workers_pool_t *pool;
size_t frame_size = frame_get_generous_size(RUN(width), RUN(height));
LOG_INFO("Creating pool with %u workers ...", stream->encoder->run->n_workers);
@ -374,8 +410,9 @@ static struct _workers_pool_t *_workers_pool_init(struct stream_t *stream) {
for (unsigned number = 0; number < pool->n_workers; ++number) {
# define WR(_next) pool->workers[number]._next
WR(frame) = frame_init();
frame_realloc_data(WR(frame), frame_size);
A_CALLOC(WR(frame_role), 32);
sprintf(WR(frame_role), "worker_dest_%u", number);
WR(frame) = frame_init(WR(frame_role));
A_MUTEX_INIT(&WR(has_job_mutex));
atomic_init(&WR(has_job), false);
@ -417,6 +454,7 @@ static void _workers_pool_destroy(struct _workers_pool_t *pool) {
A_COND_DESTROY(&WR(has_job_cond));
frame_destroy(WR(frame));
free(WR(frame_role));
# undef WR
}

View File

@ -35,6 +35,8 @@
#include "../common/threading.h"
#include "../common/logging.h"
#include "blank.h"
#include "frame.h"
#include "device.h"
#include "encoder.h"
@ -56,10 +58,12 @@ struct video_t {
bool online;
unsigned captured_fps;
atomic_bool updated;
long double last_as_blank_ts;
pthread_mutex_t mutex;
};
struct stream_t {
int last_as_blank;
unsigned error_delay;
# ifdef WITH_RAWSINK
char *rawsink_name;
@ -69,6 +73,7 @@ struct stream_t {
struct device_t *dev;
struct encoder_t *encoder;
struct frame_t *blank;
struct process_t *proc;
struct video_t *video;