mirror of
https://github.com/pikvm/ustreamer.git
synced 2026-03-14 11:33:43 +00:00
refactoring
This commit is contained in:
@@ -80,7 +80,7 @@ static const struct {
|
|||||||
{"USERPTR", V4L2_MEMORY_USERPTR},
|
{"USERPTR", V4L2_MEMORY_USERPTR},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int _device_consume_event(us_device_s *dev);
|
||||||
static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer *dest);
|
static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer *dest);
|
||||||
static bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, const u8 *data);
|
static bool _device_is_buffer_valid(us_device_s *dev, const struct v4l2_buffer *buf, const u8 *data);
|
||||||
static int _device_open_check_cap(us_device_s *dev);
|
static int _device_open_check_cap(us_device_s *dev);
|
||||||
@@ -258,7 +258,7 @@ void us_device_close(us_device_s *dev) {
|
|||||||
run->persistent_timeout_reported = false;
|
run->persistent_timeout_reported = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int us_device_select(us_device_s *dev, bool *has_read, bool *has_error) {
|
int us_device_wait_buffer(us_device_s *dev) {
|
||||||
us_device_runtime_s *const run = dev->run;
|
us_device_runtime_s *const run = dev->run;
|
||||||
|
|
||||||
# define INIT_FD_SET(x_set) \
|
# define INIT_FD_SET(x_set) \
|
||||||
@@ -277,19 +277,21 @@ int us_device_select(us_device_s *dev, bool *has_read, bool *has_error) {
|
|||||||
|
|
||||||
_D_LOG_DEBUG("Calling select() on video device ...");
|
_D_LOG_DEBUG("Calling select() on video device ...");
|
||||||
|
|
||||||
int retval = select(run->fd + 1, &read_fds, NULL, &error_fds, &timeout);
|
bool has_read = false;
|
||||||
if (retval > 0) {
|
bool has_error = false;
|
||||||
*has_read = FD_ISSET(run->fd, &read_fds);
|
const int selected = select(run->fd + 1, &read_fds, NULL, &error_fds, &timeout);
|
||||||
*has_error = FD_ISSET(run->fd, &error_fds);
|
if (selected > 0) {
|
||||||
} else {
|
has_read = FD_ISSET(run->fd, &read_fds);
|
||||||
*has_read = false;
|
has_error = FD_ISSET(run->fd, &error_fds);
|
||||||
*has_error = false;
|
|
||||||
}
|
}
|
||||||
_D_LOG_DEBUG("Device select() --> %d; has_read=%d, has_error=%d", retval, *has_read, *has_error);
|
_D_LOG_DEBUG("Device select() --> %d; has_read=%d, has_error=%d", selected, has_read, has_error);
|
||||||
|
|
||||||
if (retval > 0) {
|
if (selected < 0) {
|
||||||
run->persistent_timeout_reported = false;
|
if (errno != EINTR) {
|
||||||
} else if (retval == 0) {
|
_D_LOG_PERROR("Device select() error");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (selected == 0) {
|
||||||
if (dev->persistent) {
|
if (dev->persistent) {
|
||||||
if (!run->persistent_timeout_reported) {
|
if (!run->persistent_timeout_reported) {
|
||||||
_D_LOG_ERROR("Persistent device timeout (unplugged)");
|
_D_LOG_ERROR("Persistent device timeout (unplugged)");
|
||||||
@@ -297,10 +299,33 @@ int us_device_select(us_device_s *dev, bool *has_read, bool *has_error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Если устройство не персистентное, то таймаут является ошибкой
|
// Если устройство не персистентное, то таймаут является ошибкой
|
||||||
retval = -1;
|
return -1;
|
||||||
|
}
|
||||||
|
return -2; // No new frames
|
||||||
|
} else {
|
||||||
|
run->persistent_timeout_reported = false;
|
||||||
|
if (has_error && _device_consume_event(dev) < 0) {
|
||||||
|
return -1; // Restart required
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _device_consume_event(us_device_s *dev) {
|
||||||
|
struct v4l2_event event;
|
||||||
|
if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) < 0) {
|
||||||
|
_D_LOG_PERROR("Can't consume V4L2 event");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
switch (event.type) {
|
||||||
|
case V4L2_EVENT_SOURCE_CHANGE:
|
||||||
|
_D_LOG_INFO("Got V4L2_EVENT_SOURCE_CHANGE: Source changed");
|
||||||
|
return -1;
|
||||||
|
case V4L2_EVENT_EOS:
|
||||||
|
_D_LOG_INFO("Got V4L2_EVENT_EOS: End of stream");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw) {
|
||||||
@@ -419,24 +444,6 @@ int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int us_device_consume_event(us_device_s *dev) {
|
|
||||||
struct v4l2_event event;
|
|
||||||
_D_LOG_INFO("Consuming V4L2 event ...");
|
|
||||||
if (us_xioctl(dev->run->fd, VIDIOC_DQEVENT, &event) == 0) {
|
|
||||||
switch (event.type) {
|
|
||||||
case V4L2_EVENT_SOURCE_CHANGE:
|
|
||||||
_D_LOG_INFO("Got V4L2_EVENT_SOURCE_CHANGE: source changed");
|
|
||||||
return -1;
|
|
||||||
case V4L2_EVENT_EOS:
|
|
||||||
_D_LOG_INFO("Got V4L2_EVENT_EOS: end of stream (ignored)");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_D_LOG_PERROR("Got some V4L2 device event, but where is it? ");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer *dest) {
|
static void _v4l2_buffer_copy(const struct v4l2_buffer *src, struct v4l2_buffer *dest) {
|
||||||
struct v4l2_plane *dest_planes = dest->m.planes;
|
struct v4l2_plane *dest_planes = dest->m.planes;
|
||||||
memcpy(dest, src, sizeof(struct v4l2_buffer));
|
memcpy(dest, src, sizeof(struct v4l2_buffer));
|
||||||
|
|||||||
@@ -132,7 +132,6 @@ int us_device_parse_io_method(const char *str);
|
|||||||
int us_device_open(us_device_s *dev);
|
int us_device_open(us_device_s *dev);
|
||||||
void us_device_close(us_device_s *dev);
|
void us_device_close(us_device_s *dev);
|
||||||
|
|
||||||
int us_device_select(us_device_s *dev, bool *has_read, bool *has_error);
|
int us_device_wait_buffer(us_device_s *dev);
|
||||||
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw);
|
int us_device_grab_buffer(us_device_s *dev, us_hw_buffer_s **hw);
|
||||||
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw);
|
int us_device_release_buffer(us_device_s *dev, us_hw_buffer_s *hw);
|
||||||
int us_device_consume_event(us_device_s *dev);
|
|
||||||
|
|||||||
@@ -120,68 +120,55 @@ void us_stream_loop(us_stream_s *stream) {
|
|||||||
goto close;
|
goto close;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_read;
|
switch (us_device_wait_buffer(stream->dev)) {
|
||||||
bool has_error;
|
case 0: break; // New frame
|
||||||
const int selected = us_device_select(stream->dev, &has_read, &has_error);
|
case -2: // Persistent timeout
|
||||||
|
|
||||||
if (selected < 0) {
|
|
||||||
if (errno != EINTR) {
|
|
||||||
US_LOG_PERROR("Mainloop select() error");
|
|
||||||
goto close;
|
|
||||||
}
|
|
||||||
} else if (selected == 0) { // Persistent timeout
|
|
||||||
# ifdef WITH_GPIO
|
|
||||||
us_gpio_set_stream_online(false);
|
|
||||||
# endif
|
|
||||||
} else {
|
|
||||||
if (has_read) {
|
|
||||||
# ifdef WITH_GPIO
|
# ifdef WITH_GPIO
|
||||||
us_gpio_set_stream_online(true);
|
us_gpio_set_stream_online(false);
|
||||||
# endif
|
# endif
|
||||||
|
goto close;
|
||||||
|
default: goto close; // Error
|
||||||
|
}
|
||||||
|
|
||||||
const long double now = us_get_now_monotonic();
|
# ifdef WITH_GPIO
|
||||||
const long long now_second = us_floor_ms(now);
|
us_gpio_set_stream_online(true);
|
||||||
|
# endif
|
||||||
|
|
||||||
us_hw_buffer_s *hw;
|
const long double now = us_get_now_monotonic();
|
||||||
const int buf_index = us_device_grab_buffer(stream->dev, &hw);
|
const long long now_second = us_floor_ms(now);
|
||||||
|
|
||||||
if (buf_index >= 0) {
|
us_hw_buffer_s *hw;
|
||||||
if (now < grab_after) {
|
const int buf_index = us_device_grab_buffer(stream->dev, &hw);
|
||||||
fluency_passed += 1;
|
|
||||||
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) {
|
|
||||||
goto close;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fluency_passed = 0;
|
|
||||||
|
|
||||||
if (now_second != captured_fps_second) {
|
if (buf_index >= 0) {
|
||||||
US_LOG_PERF_FPS("A new second has come; captured_fps=%u", captured_fps_accum);
|
if (now < grab_after) {
|
||||||
atomic_store(&run->captured_fps, captured_fps_accum);
|
fluency_passed += 1;
|
||||||
captured_fps_accum = 0;
|
US_LOG_VERBOSE("Passed %u frames for fluency: now=%.03Lf, grab_after=%.03Lf",
|
||||||
captured_fps_second = now_second;
|
fluency_passed, now, grab_after);
|
||||||
}
|
if (us_device_release_buffer(stream->dev, hw) < 0) {
|
||||||
captured_fps_accum += 1;
|
|
||||||
|
|
||||||
const long double fluency_delay = us_workers_pool_get_fluency_delay(stream->enc->run->pool, ready_wr);
|
|
||||||
grab_after = now + fluency_delay;
|
|
||||||
US_LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after);
|
|
||||||
|
|
||||||
ready_job->hw = hw;
|
|
||||||
us_workers_pool_assign(stream->enc->run->pool, ready_wr);
|
|
||||||
US_LOG_DEBUG("Assigned new frame in buffer=%d to worker=%s", buf_index, ready_wr->name);
|
|
||||||
|
|
||||||
_SINK_PUT(raw_sink, &hw->raw);
|
|
||||||
_H264_PUT(&hw->raw, h264_force_key);
|
|
||||||
}
|
|
||||||
} else if (buf_index != -2) { // -2 for broken frame
|
|
||||||
goto close;
|
goto close;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
fluency_passed = 0;
|
||||||
|
|
||||||
if (has_error && us_device_consume_event(stream->dev) < 0) {
|
if (now_second != captured_fps_second) {
|
||||||
goto close;
|
US_LOG_PERF_FPS("A new second has come; captured_fps=%u", captured_fps_accum);
|
||||||
|
atomic_store(&run->captured_fps, captured_fps_accum);
|
||||||
|
captured_fps_accum = 0;
|
||||||
|
captured_fps_second = now_second;
|
||||||
|
}
|
||||||
|
captured_fps_accum += 1;
|
||||||
|
|
||||||
|
const long double fluency_delay = us_workers_pool_get_fluency_delay(stream->enc->run->pool, ready_wr);
|
||||||
|
grab_after = now + fluency_delay;
|
||||||
|
US_LOG_VERBOSE("Fluency: delay=%.03Lf, grab_after=%.03Lf", fluency_delay, grab_after);
|
||||||
|
|
||||||
|
ready_job->hw = hw;
|
||||||
|
us_workers_pool_assign(stream->enc->run->pool, ready_wr);
|
||||||
|
US_LOG_DEBUG("Assigned new frame in buffer=%d to worker=%s", buf_index, ready_wr->name);
|
||||||
|
|
||||||
|
_SINK_PUT(raw_sink, &hw->raw);
|
||||||
|
_H264_PUT(&hw->raw, h264_force_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,40 +216,29 @@ static void _main_loop(void) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_read;
|
switch (us_device_wait_buffer(dev)) {
|
||||||
bool has_error;
|
case 0: break; // New frame
|
||||||
const int selected = us_device_select(dev, &has_read, &has_error);
|
case -2: // Persistent timeout
|
||||||
|
if (us_drm_expose(drm, US_DRM_EXPOSE_NO_SIGNAL, NULL, 0) < 0) {
|
||||||
|
_slowdown();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
default: goto close; // Error
|
||||||
|
}
|
||||||
|
|
||||||
if (selected < 0) {
|
us_hw_buffer_s *hw;
|
||||||
if (errno != EINTR) {
|
const int buf_index = us_device_grab_buffer(dev, &hw);
|
||||||
US_LOG_PERROR("Mainloop select() error");
|
if (buf_index >= 0) {
|
||||||
|
const int exposed = us_drm_expose(drm, US_DRM_EXPOSE_FRAME, &hw->raw, dev->run->hz);
|
||||||
|
if (us_device_release_buffer(dev, hw) < 0) {
|
||||||
goto close;
|
goto close;
|
||||||
}
|
}
|
||||||
} else if (selected == 0) { // Persistent timeout
|
if (exposed < 0) {
|
||||||
if (us_drm_expose(drm, US_DRM_EXPOSE_NO_SIGNAL, NULL, 0) < 0) {
|
|
||||||
_slowdown();
|
_slowdown();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (buf_index != -2) { // -2 for broken frame
|
||||||
if (has_read) {
|
goto close;
|
||||||
us_hw_buffer_s *hw;
|
|
||||||
const int buf_index = us_device_grab_buffer(dev, &hw);
|
|
||||||
if (buf_index >= 0) {
|
|
||||||
const int exposed = us_drm_expose(drm, US_DRM_EXPOSE_FRAME, &hw->raw, dev->run->hz);
|
|
||||||
if (us_device_release_buffer(dev, hw) < 0) {
|
|
||||||
goto close;
|
|
||||||
}
|
|
||||||
if (exposed < 0) {
|
|
||||||
_slowdown();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if (buf_index != -2) { // -2 for broken frame
|
|
||||||
goto close;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has_error && us_device_consume_event(dev) < 0) {
|
|
||||||
goto close;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user