mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-04-14 18:46:13 +00:00
refactoring
This commit is contained in:
@@ -30,8 +30,6 @@ static int _stream_init_loop(us_stream_s *stream);
|
|||||||
static void _stream_expose_frame(us_stream_s *stream, us_frame_s *frame);
|
static void _stream_expose_frame(us_stream_s *stream, us_frame_s *frame);
|
||||||
|
|
||||||
|
|
||||||
#define _RUN(x_next) stream->run->x_next
|
|
||||||
|
|
||||||
#define _SINK_PUT(x_sink, x_frame) { \
|
#define _SINK_PUT(x_sink, x_frame) { \
|
||||||
if (stream->x_sink && us_memsink_server_check(stream->x_sink, x_frame)) {\
|
if (stream->x_sink && us_memsink_server_check(stream->x_sink, x_frame)) {\
|
||||||
bool m_key_requested; /* Unused */ \
|
bool m_key_requested; /* Unused */ \
|
||||||
@@ -40,8 +38,8 @@ static void _stream_expose_frame(us_stream_s *stream, us_frame_s *frame);
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define _H264_PUT(x_frame, x_force_key) { \
|
#define _H264_PUT(x_frame, x_force_key) { \
|
||||||
if (_RUN(h264)) { \
|
if (stream->run->h264) { \
|
||||||
us_h264_stream_process(_RUN(h264), x_frame, x_force_key); \
|
us_h264_stream_process(stream->run->h264, x_frame, x_force_key); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,13 +74,15 @@ void us_stream_destroy(us_stream_s *stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void us_stream_loop(us_stream_s *stream) {
|
void us_stream_loop(us_stream_s *stream) {
|
||||||
|
us_stream_runtime_s *const run = stream->run;
|
||||||
|
|
||||||
US_LOG_INFO("Using V4L2 device: %s", stream->dev->path);
|
US_LOG_INFO("Using V4L2 device: %s", stream->dev->path);
|
||||||
US_LOG_INFO("Using desired FPS: %u", stream->dev->desired_fps);
|
US_LOG_INFO("Using desired FPS: %u", stream->dev->desired_fps);
|
||||||
|
|
||||||
atomic_store(&stream->run->http_last_request_ts, us_get_now_monotonic());
|
atomic_store(&run->http_last_request_ts, us_get_now_monotonic());
|
||||||
|
|
||||||
if (stream->h264_sink != NULL) {
|
if (stream->h264_sink != NULL) {
|
||||||
_RUN(h264) = us_h264_stream_init(stream->h264_sink, stream->h264_m2m_path, stream->h264_bitrate, stream->h264_gop);
|
run->h264 = us_h264_stream_init(stream->h264_sink, stream->h264_m2m_path, stream->h264_bitrate, stream->h264_gop);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!_stream_init_loop(stream)) {
|
while (!_stream_init_loop(stream)) {
|
||||||
@@ -102,7 +102,7 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
|
|
||||||
if (ready_job->hw != NULL) {
|
if (ready_job->hw != NULL) {
|
||||||
if (us_device_release_buffer(stream->dev, ready_job->hw) < 0) {
|
if (us_device_release_buffer(stream->dev, ready_job->hw) < 0) {
|
||||||
break;
|
goto close;
|
||||||
}
|
}
|
||||||
if (ready_wr->job_failed) {
|
if (ready_wr->job_failed) {
|
||||||
// pass
|
// pass
|
||||||
@@ -117,7 +117,7 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
|
|
||||||
const bool h264_force_key = _stream_slowdown(stream);
|
const bool h264_force_key = _stream_slowdown(stream);
|
||||||
if (_stream_is_stopped(stream)) {
|
if (_stream_is_stopped(stream)) {
|
||||||
break;
|
goto close;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_read;
|
bool has_read;
|
||||||
@@ -127,7 +127,7 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
if (selected < 0) {
|
if (selected < 0) {
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
US_LOG_PERROR("Mainloop select() error");
|
US_LOG_PERROR("Mainloop select() error");
|
||||||
break;
|
goto close;
|
||||||
}
|
}
|
||||||
} else if (selected == 0) { // Persistent timeout
|
} else if (selected == 0) { // Persistent timeout
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
@@ -151,14 +151,14 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
US_LOG_VERBOSE("Passed %u frames for fluency: now=%.03Lf, grab_after=%.03Lf",
|
US_LOG_VERBOSE("Passed %u frames for fluency: now=%.03Lf, grab_after=%.03Lf",
|
||||||
fluency_passed, now, grab_after);
|
fluency_passed, now, grab_after);
|
||||||
if (us_device_release_buffer(stream->dev, hw) < 0) {
|
if (us_device_release_buffer(stream->dev, hw) < 0) {
|
||||||
break;
|
goto close;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fluency_passed = 0;
|
fluency_passed = 0;
|
||||||
|
|
||||||
if (now_second != captured_fps_second) {
|
if (now_second != captured_fps_second) {
|
||||||
US_LOG_PERF_FPS("A new second has come; captured_fps=%u", captured_fps_accum);
|
US_LOG_PERF_FPS("A new second has come; captured_fps=%u", captured_fps_accum);
|
||||||
atomic_store(&stream->run->captured_fps, captured_fps_accum);
|
atomic_store(&run->captured_fps, captured_fps_accum);
|
||||||
captured_fps_accum = 0;
|
captured_fps_accum = 0;
|
||||||
captured_fps_second = now_second;
|
captured_fps_second = now_second;
|
||||||
}
|
}
|
||||||
@@ -176,16 +176,17 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
_H264_PUT(&hw->raw, h264_force_key);
|
_H264_PUT(&hw->raw, h264_force_key);
|
||||||
}
|
}
|
||||||
} else if (buf_index != -2) { // -2 for broken frame
|
} else if (buf_index != -2) { // -2 for broken frame
|
||||||
break;
|
goto close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_error && us_device_consume_event(stream->dev) < 0) {
|
if (has_error && us_device_consume_event(stream->dev) < 0) {
|
||||||
break;
|
goto close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close:
|
||||||
us_encoder_close(stream->enc);
|
us_encoder_close(stream->enc);
|
||||||
us_device_close(stream->dev);
|
us_device_close(stream->dev);
|
||||||
|
|
||||||
@@ -194,39 +195,41 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
US_DELETE(_RUN(h264), us_h264_stream_destroy);
|
US_DELETE(run->h264, us_h264_stream_destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
void us_stream_loop_break(us_stream_s *stream) {
|
void us_stream_loop_break(us_stream_s *stream) {
|
||||||
atomic_store(&_RUN(stop), true);
|
atomic_store(&stream->run->stop, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _stream_is_stopped(us_stream_s *stream) {
|
static bool _stream_is_stopped(us_stream_s *stream) {
|
||||||
const bool stop = atomic_load(&_RUN(stop));
|
us_stream_runtime_s *const run = stream->run;
|
||||||
|
const bool stop = atomic_load(&run->stop);
|
||||||
if (stop) {
|
if (stop) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (stream->exit_on_no_clients > 0) {
|
if (stream->exit_on_no_clients > 0) {
|
||||||
const long double now = us_get_now_monotonic();
|
const long double now = us_get_now_monotonic();
|
||||||
const uint64_t http_last_request_ts = atomic_load(&_RUN(http_last_request_ts)); // Seconds
|
const uint64_t http_last_request_ts = atomic_load(&run->http_last_request_ts); // Seconds
|
||||||
if (_stream_has_any_clients(stream)) {
|
if (_stream_has_any_clients(stream)) {
|
||||||
atomic_store(&_RUN(http_last_request_ts), now);
|
atomic_store(&run->http_last_request_ts, now);
|
||||||
} else if (http_last_request_ts + stream->exit_on_no_clients < now) {
|
} else if (http_last_request_ts + stream->exit_on_no_clients < now) {
|
||||||
US_LOG_INFO("No requests or HTTP/sink clients found in last %u seconds, exiting ...",
|
US_LOG_INFO("No requests or HTTP/sink clients found in last %u seconds, exiting ...",
|
||||||
stream->exit_on_no_clients);
|
stream->exit_on_no_clients);
|
||||||
us_process_suicide();
|
us_process_suicide();
|
||||||
atomic_store(&_RUN(http_last_request_ts), now);
|
atomic_store(&run->http_last_request_ts, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _stream_has_any_clients(us_stream_s *stream) {
|
static bool _stream_has_any_clients(us_stream_s *stream) {
|
||||||
|
us_stream_runtime_s *const run = stream->run;
|
||||||
return (
|
return (
|
||||||
atomic_load(&_RUN(http_has_clients))
|
atomic_load(&run->http_has_clients)
|
||||||
// has_clients синков НЕ обновляются в реальном времени
|
// has_clients синков НЕ обновляются в реальном времени
|
||||||
|| (stream->sink != NULL && atomic_load(&stream->sink->has_clients))
|
|| (stream->sink != NULL && atomic_load(&stream->sink->has_clients))
|
||||||
|| (_RUN(h264) != NULL && /*_RUN(h264->sink) == NULL ||*/ atomic_load(&_RUN(h264->sink->has_clients)))
|
|| (run->h264 != NULL && /*run->h264->sink == NULL ||*/ atomic_load(&run->h264->sink->has_clients))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,6 +246,8 @@ static bool _stream_slowdown(us_stream_s *stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int _stream_init_loop(us_stream_s *stream) {
|
static int _stream_init_loop(us_stream_s *stream) {
|
||||||
|
us_stream_runtime_s *const run = stream->run;
|
||||||
|
|
||||||
int access_errno = 0;
|
int access_errno = 0;
|
||||||
while (!_stream_is_stopped(stream)) {
|
while (!_stream_is_stopped(stream)) {
|
||||||
unsigned width = stream->dev->run->width;
|
unsigned width = stream->dev->run->width;
|
||||||
@@ -251,13 +256,13 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
width = stream->dev->width;
|
width = stream->dev->width;
|
||||||
height = stream->dev->height;
|
height = stream->dev->height;
|
||||||
}
|
}
|
||||||
us_blank_draw(stream->run->blank, "< NO SIGNAL >", width, height);
|
us_blank_draw(run->blank, "< NO SIGNAL >", width, height);
|
||||||
|
|
||||||
atomic_store(&stream->run->captured_fps, 0);
|
atomic_store(&run->captured_fps, 0);
|
||||||
_stream_expose_frame(stream, NULL);
|
_stream_expose_frame(stream, NULL);
|
||||||
|
|
||||||
_SINK_PUT(raw_sink, stream->run->blank->raw);
|
_SINK_PUT(raw_sink, run->blank->raw);
|
||||||
_H264_PUT(stream->run->blank->raw, false);
|
_H264_PUT(run->blank->raw, false);
|
||||||
|
|
||||||
if (access(stream->dev->path, R_OK|W_OK) < 0) {
|
if (access(stream->dev->path, R_OK|W_OK) < 0) {
|
||||||
if (access_errno != errno) {
|
if (access_errno != errno) {
|
||||||
@@ -275,7 +280,7 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
stream->dev->dma_export = (
|
stream->dev->dma_export = (
|
||||||
stream->enc->type == US_ENCODER_TYPE_M2M_VIDEO
|
stream->enc->type == US_ENCODER_TYPE_M2M_VIDEO
|
||||||
|| stream->enc->type == US_ENCODER_TYPE_M2M_IMAGE
|
|| stream->enc->type == US_ENCODER_TYPE_M2M_IMAGE
|
||||||
|| _RUN(h264) != NULL
|
|| run->h264 != NULL
|
||||||
);
|
);
|
||||||
if (us_device_open(stream->dev) == 0) {
|
if (us_device_open(stream->dev) == 0) {
|
||||||
us_encoder_open(stream->enc, stream->dev);
|
us_encoder_open(stream->enc, stream->dev);
|
||||||
@@ -291,38 +296,37 @@ static int _stream_init_loop(us_stream_s *stream) {
|
|||||||
|
|
||||||
static void _stream_expose_frame(us_stream_s *stream, us_frame_s *frame) {
|
static void _stream_expose_frame(us_stream_s *stream, us_frame_s *frame) {
|
||||||
us_stream_runtime_s *const run = stream->run;
|
us_stream_runtime_s *const run = stream->run;
|
||||||
us_blank_s *const blank = run->blank;
|
|
||||||
|
|
||||||
us_frame_s *new = NULL;
|
us_frame_s *new = NULL;
|
||||||
|
|
||||||
if (frame != NULL) {
|
if (frame != NULL) {
|
||||||
new = frame;
|
new = frame;
|
||||||
_RUN(last_as_blank_ts) = 0; // Останавливаем таймер
|
run->last_as_blank_ts = 0; // Останавливаем таймер
|
||||||
US_LOG_DEBUG("Exposed ALIVE video frame");
|
US_LOG_DEBUG("Exposed ALIVE video frame");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (run->last_online) { // Если переходим из online в offline
|
if (run->last_online) { // Если переходим из online в offline
|
||||||
if (stream->last_as_blank < 0) { // Если last_as_blank выключен, просто покажем старую картинку
|
if (stream->last_as_blank < 0) { // Если last_as_blank выключен, просто покажем старую картинку
|
||||||
new = blank->jpeg;
|
new = run->blank->jpeg;
|
||||||
US_LOG_INFO("Changed video frame to BLANK");
|
US_LOG_INFO("Changed video frame to BLANK");
|
||||||
} else if (stream->last_as_blank > 0) { // // Если нужен таймер - запустим
|
} else if (stream->last_as_blank > 0) { // // Если нужен таймер - запустим
|
||||||
_RUN(last_as_blank_ts) = us_get_now_monotonic() + stream->last_as_blank;
|
run->last_as_blank_ts = us_get_now_monotonic() + stream->last_as_blank;
|
||||||
US_LOG_INFO("Freezed last ALIVE video frame for %d seconds", stream->last_as_blank);
|
US_LOG_INFO("Freezed last ALIVE video frame for %d seconds", stream->last_as_blank);
|
||||||
} else { // last_as_blank == 0 - показываем последний фрейм вечно
|
} else { // last_as_blank == 0 - показываем последний фрейм вечно
|
||||||
US_LOG_INFO("Freezed last ALIVE video frame forever");
|
US_LOG_INFO("Freezed last ALIVE video frame forever");
|
||||||
}
|
}
|
||||||
} else if (stream->last_as_blank < 0) {
|
} else if (stream->last_as_blank < 0) {
|
||||||
new = blank->jpeg;
|
new = run->blank->jpeg;
|
||||||
// US_LOG_INFO("Changed video frame to BLANK");
|
// US_LOG_INFO("Changed video frame to BLANK");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( // Если уже оффлайн, включена фича last_as_blank с таймером и он запущен
|
if ( // Если уже оффлайн, включена фича last_as_blank с таймером и он запущен
|
||||||
stream->last_as_blank > 0
|
stream->last_as_blank > 0
|
||||||
&& _RUN(last_as_blank_ts) != 0
|
&& run->last_as_blank_ts != 0
|
||||||
&& _RUN(last_as_blank_ts) < us_get_now_monotonic()
|
&& run->last_as_blank_ts < us_get_now_monotonic()
|
||||||
) {
|
) {
|
||||||
new = blank->jpeg;
|
new = run->blank->jpeg;
|
||||||
_RUN(last_as_blank_ts) = 0; // Останавливаем таймер
|
run->last_as_blank_ts = 0; // Останавливаем таймер
|
||||||
US_LOG_INFO("Changed last ALIVE video frame to BLANK");
|
US_LOG_INFO("Changed last ALIVE video frame to BLANK");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,5 +353,5 @@ static void _stream_expose_frame(us_stream_s *stream, us_frame_s *frame) {
|
|||||||
run->last_online = (frame != NULL);
|
run->last_online = (frame != NULL);
|
||||||
us_ring_producer_release(run->http_jpeg_ring, ri);
|
us_ring_producer_release(run->http_jpeg_ring, ri);
|
||||||
|
|
||||||
_SINK_PUT(sink, (frame != NULL ? frame : blank->jpeg));
|
_SINK_PUT(sink, (frame != NULL ? frame : run->blank->jpeg));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user