/* Плавно меняет потолок QP по выходному видеобитрейту. Один video worker, время в микросекундах. * reset вызывается при смене пользовательских настроек/encoder. update учитывает только новые encoded bytes. * Выбранный потолок — нижняя граница адаптации: при перерасходе допускается рост до 51, затем возврат. */ #pragma once #include class StreamQpControl { int m_base = -1, m_limit = -1, m_target = 0; bool m_adaptive = false, m_sampled = false; int64_t m_at = 0; uint64_t m_bytes = 0, m_bitrate = 0; public: void reset(int base, int target, bool adaptive, int64_t now) { m_base = m_limit = base; m_target = target; m_adaptive = adaptive; m_at = now; m_bytes = m_bitrate = 0; m_sampled = false; } int limit() const { return m_limit; } uint64_t bitrate() const { return m_bitrate; } // Сглаженный выходной битрейт, бит/с. int update(uint64_t bytes, int64_t now) { m_bytes += bytes; const int64_t elapsed = now - m_at; if (elapsed < 2000000) return m_limit; const uint64_t measured = m_bytes * 8000000 / elapsed; m_bitrate = m_sampled ? (m_bitrate + measured) / 2 : measured; m_sampled = true; m_bytes = 0; m_at = now; if (!m_adaptive || m_base < 0 || m_target <= 0) return m_limit; if (measured > uint64_t(m_target) * 108 / 100 && m_bitrate > uint64_t(m_target) * 108 / 100 && m_limit < 51) ++m_limit; else if (m_bitrate < uint64_t(m_target) * 90 / 100 && m_limit > m_base) --m_limit; return m_limit; } };