mirror of
https://github.com/pikvm/ustreamer.git
synced 2025-12-24 03:00:01 +00:00
refactoring
This commit is contained in:
parent
cfc5ae1b94
commit
6145b69c97
@ -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);
|
||||
|
||||
|
||||
#define _RUN(x_next) stream->run->x_next
|
||||
|
||||
#define _SINK_PUT(x_sink, x_frame) { \
|
||||
if (stream->x_sink && us_memsink_server_check(stream->x_sink, x_frame)) {\
|
||||
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) { \
|
||||
if (_RUN(h264)) { \
|
||||
us_h264_stream_process(_RUN(h264), x_frame, x_force_key); \
|
||||
if (stream->run->h264) { \
|
||||
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) {
|
||||
us_stream_runtime_s *const run = stream->run;
|
||||
|
||||
US_LOG_INFO("Using V4L2 device: %s", stream->dev->path);
|
||||
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) {
|
||||
_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)) {
|
||||
@ -102,7 +102,7 @@ void us_stream_loop(us_stream_s *stream) {
|
||||
|
||||
if (ready_job->hw != NULL) {
|
||||
if (us_device_release_buffer(stream->dev, ready_job->hw) < 0) {
|
||||
break;
|
||||
goto close;
|
||||
}
|
||||
if (ready_wr->job_failed) {
|
||||
// pass
|
||||
@ -117,7 +117,7 @@ void us_stream_loop(us_stream_s *stream) {
|
||||
|
||||
const bool h264_force_key = _stream_slowdown(stream);
|
||||
if (_stream_is_stopped(stream)) {
|
||||
break;
|
||||
goto close;
|
||||
}
|
||||
|
||||
bool has_read;
|
||||
@ -127,7 +127,7 @@ void us_stream_loop(us_stream_s *stream) {
|
||||
if (selected < 0) {
|
||||
if (errno != EINTR) {
|
||||
US_LOG_PERROR("Mainloop select() error");
|
||||
break;
|
||||
goto close;
|
||||
}
|
||||
} else if (selected == 0) { // Persistent timeout
|
||||
# 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",
|
||||
fluency_passed, now, grab_after);
|
||||
if (us_device_release_buffer(stream->dev, hw) < 0) {
|
||||
break;
|
||||
goto close;
|
||||
}
|
||||
} else {
|
||||
fluency_passed = 0;
|
||||
|
||||
if (now_second != captured_fps_second) {
|
||||
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_second = now_second;
|
||||
}
|
||||
@ -176,16 +176,17 @@ void us_stream_loop(us_stream_s *stream) {
|
||||
_H264_PUT(&hw->raw, h264_force_key);
|
||||
}
|
||||
} else if (buf_index != -2) { // -2 for broken frame
|
||||
break;
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_error && us_device_consume_event(stream->dev) < 0) {
|
||||
break;
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close:
|
||||
us_encoder_close(stream->enc);
|
||||
us_device_close(stream->dev);
|
||||
|
||||
@ -194,39 +195,41 @@ void us_stream_loop(us_stream_s *stream) {
|
||||
# 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) {
|
||||
atomic_store(&_RUN(stop), true);
|
||||
atomic_store(&stream->run->stop, true);
|
||||
}
|
||||
|
||||
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) {
|
||||
return true;
|
||||
}
|
||||
if (stream->exit_on_no_clients > 0) {
|
||||
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)) {
|
||||
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) {
|
||||
US_LOG_INFO("No requests or HTTP/sink clients found in last %u seconds, exiting ...",
|
||||
stream->exit_on_no_clients);
|
||||
us_process_suicide();
|
||||
atomic_store(&_RUN(http_last_request_ts), now);
|
||||
atomic_store(&run->http_last_request_ts, now);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _stream_has_any_clients(us_stream_s *stream) {
|
||||
us_stream_runtime_s *const run = stream->run;
|
||||
return (
|
||||
atomic_load(&_RUN(http_has_clients))
|
||||
atomic_load(&run->http_has_clients)
|
||||
// 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) {
|
||||
us_stream_runtime_s *const run = stream->run;
|
||||
|
||||
int access_errno = 0;
|
||||
while (!_stream_is_stopped(stream)) {
|
||||
unsigned width = stream->dev->run->width;
|
||||
@ -251,13 +256,13 @@ static int _stream_init_loop(us_stream_s *stream) {
|
||||
width = stream->dev->width;
|
||||
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);
|
||||
|
||||
_SINK_PUT(raw_sink, stream->run->blank->raw);
|
||||
_H264_PUT(stream->run->blank->raw, false);
|
||||
_SINK_PUT(raw_sink, run->blank->raw);
|
||||
_H264_PUT(run->blank->raw, false);
|
||||
|
||||
if (access(stream->dev->path, R_OK|W_OK) < 0) {
|
||||
if (access_errno != errno) {
|
||||
@ -275,7 +280,7 @@ static int _stream_init_loop(us_stream_s *stream) {
|
||||
stream->dev->dma_export = (
|
||||
stream->enc->type == US_ENCODER_TYPE_M2M_VIDEO
|
||||
|| stream->enc->type == US_ENCODER_TYPE_M2M_IMAGE
|
||||
|| _RUN(h264) != NULL
|
||||
|| run->h264 != NULL
|
||||
);
|
||||
if (us_device_open(stream->dev) == 0) {
|
||||
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) {
|
||||
us_stream_runtime_s *const run = stream->run;
|
||||
us_blank_s *const blank = run->blank;
|
||||
|
||||
us_frame_s *new = NULL;
|
||||
|
||||
if (frame != NULL) {
|
||||
new = frame;
|
||||
_RUN(last_as_blank_ts) = 0; // Останавливаем таймер
|
||||
run->last_as_blank_ts = 0; // Останавливаем таймер
|
||||
US_LOG_DEBUG("Exposed ALIVE video frame");
|
||||
|
||||
} else {
|
||||
if (run->last_online) { // Если переходим из online в offline
|
||||
if (stream->last_as_blank < 0) { // Если last_as_blank выключен, просто покажем старую картинку
|
||||
new = blank->jpeg;
|
||||
new = run->blank->jpeg;
|
||||
US_LOG_INFO("Changed video frame to BLANK");
|
||||
} 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);
|
||||
} else { // last_as_blank == 0 - показываем последний фрейм вечно
|
||||
US_LOG_INFO("Freezed last ALIVE video frame forever");
|
||||
}
|
||||
} else if (stream->last_as_blank < 0) {
|
||||
new = blank->jpeg;
|
||||
new = run->blank->jpeg;
|
||||
// US_LOG_INFO("Changed video frame to BLANK");
|
||||
}
|
||||
|
||||
if ( // Если уже оффлайн, включена фича last_as_blank с таймером и он запущен
|
||||
stream->last_as_blank > 0
|
||||
&& _RUN(last_as_blank_ts) != 0
|
||||
&& _RUN(last_as_blank_ts) < us_get_now_monotonic()
|
||||
&& run->last_as_blank_ts != 0
|
||||
&& run->last_as_blank_ts < us_get_now_monotonic()
|
||||
) {
|
||||
new = blank->jpeg;
|
||||
_RUN(last_as_blank_ts) = 0; // Останавливаем таймер
|
||||
new = run->blank->jpeg;
|
||||
run->last_as_blank_ts = 0; // Останавливаем таймер
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user