new fps limiter

This commit is contained in:
Maxim Devaev 2026-01-21 07:03:58 +02:00
parent 9eb39bbfc3
commit b983b6c355

View File

@ -28,6 +28,7 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include <math.h>
#include <pthread.h> #include <pthread.h>
@ -314,6 +315,9 @@ static void *_jpeg_thread(void *v_ctx) {
_worker_context_s *ctx = v_ctx; _worker_context_s *ctx = v_ctx;
us_stream_s *stream = ctx->stream; us_stream_s *stream = ctx->stream;
uint take = 1;
uint step = 1;
ldf grab_after_ts = 0; ldf grab_after_ts = 0;
uint fluency_passed = 0; uint fluency_passed = 0;
@ -350,6 +354,19 @@ static void *_jpeg_thread(void *v_ctx) {
continue; continue;
} }
if (stream->desired_fps > 0) {
const uint captured_fps = us_fpsi_get(stream->run->http->captured_fpsi, NULL);
take = ceilf((float)captured_fps / (float)stream->desired_fps);
if (step < take) {
US_LOG_DEBUG("JPEG: Passed encoding for FPS limit: step=%u, take=%u", step, take);
++step;
us_capture_hwbuf_decref(hw);
continue;
} else {
step = 1;
}
}
const ldf now_ts = us_get_now_monotonic(); const ldf now_ts = us_get_now_monotonic();
if (now_ts < grab_after_ts) { if (now_ts < grab_after_ts) {
fluency_passed += 1; fluency_passed += 1;
@ -396,7 +413,9 @@ static void *_h264_thread(void *v_ctx) {
_worker_context_s *ctx = v_ctx; _worker_context_s *ctx = v_ctx;
us_stream_s *stream = ctx->stream; us_stream_s *stream = ctx->stream;
ldf grab_after_ts = 0; uint take = 1;
uint step = 1;
while (!atomic_load(ctx->stop)) { while (!atomic_load(ctx->stop)) {
us_capture_hwbuf_s *hw = _get_latest_hw(ctx->queue); us_capture_hwbuf_s *hw = _get_latest_hw(ctx->queue);
if (hw == NULL) { if (hw == NULL) {
@ -407,23 +426,22 @@ static void *_h264_thread(void *v_ctx) {
US_LOG_VERBOSE("H264: Passed encoding because nobody is watching"); US_LOG_VERBOSE("H264: Passed encoding because nobody is watching");
goto decref; goto decref;
} }
if (hw->raw.grab_begin_ts < grab_after_ts) {
US_LOG_DEBUG("H264: Passed encoding for FPS limit"); const uint fps_limit = US_MAX(stream->run->h264_enc->run->fps_limit, stream->desired_fps);
goto decref; if (fps_limit > 0) {
const uint captured_fps = us_fpsi_get(stream->run->http->captured_fpsi, NULL);
take = ceilf((float)captured_fps / (float)fps_limit);
if (step < take) {
US_LOG_DEBUG("H264: Passed encoding for FPS limit: step=%u, take=%u", step, take);
++step;
goto decref;
} else {
step = 1;
}
} }
_stream_encode_expose_h264(ctx->stream, &hw->raw, false); _stream_encode_expose_h264(ctx->stream, &hw->raw, false);
// M2M-енкодер увеличивает задержку на 100 милисекунд при 1080p, если скормить ему больше 30 FPS.
// Поэтому у нас есть два режима: 60 FPS для маленьких видео и 30 для 1920x1080(1200).
// Следующй фрейм захватывается не раньше, чем это требуется по FPS, минус небольшая
// погрешность (если захват неравномерный) - немного меньше 1/60, и примерно треть от 1/30.
const uint fps_limit = stream->run->h264_enc->run->fps_limit;
if (fps_limit > 0) {
const ldf frame_interval = (ldf)1 / fps_limit;
grab_after_ts = hw->raw.grab_begin_ts + frame_interval - 0.01;
}
decref: decref:
us_capture_hwbuf_decref(hw); us_capture_hwbuf_decref(hw);
} }