Use four CPU encoder workers and retain GPU priority with software fallback
This commit is contained in:
1 parent
28f3b264b8
commit
dc22014bcc
3 files changed
+11
-12
No files matched your search
@@ -17,7 +17,7 @@ bool CallVideoEncoder::open(const call_video_format& format, uint32_t bitrate, c
|
|||||||
config.bitrate = bitrate; config.references = 1; config.backend = backend;
|
config.bitrate = bitrate; config.references = 1; config.backend = backend;
|
||||||
config.profile = format.codec == CALL_VIDEO_H264 ? LiveVideoProfile::H264ConstrainedBaseline : LiveVideoProfile::H265Main;
|
config.profile = format.codec == CALL_VIDEO_H264 ? LiveVideoProfile::H264ConstrainedBaseline : LiveVideoProfile::H265Main;
|
||||||
auto candidate = std::make_unique<LiveVideoEncoder>();
|
auto candidate = std::make_unique<LiveVideoEncoder>();
|
||||||
if (!candidate->open(config, backend.isEmpty() ? LiveVideoEncoder::Backend::HardwareOnly : LiveVideoEncoder::Backend::Automatic)) {
|
if (!candidate->open(config, LiveVideoEncoder::Backend::Automatic)) {
|
||||||
m_error = candidate->error(); DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call video open failed: %s", qPrintable(m_error)); return false;
|
m_error = candidate->error(); DEBUG_ERROR(DEBUG_CATEGORY_CALL, "call video open failed: %s", qPrintable(m_error)); return false;
|
||||||
}
|
}
|
||||||
close(); m_encoder = std::move(candidate); m_config = config; m_config.backend = m_encoder->name(); m_format = format;
|
close(); m_encoder = std::move(candidate); m_config = config; m_config.backend = m_encoder->name(); m_format = format;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Кодер видеотрека звонка; только video worker, без камеры, транспорта и таймеров.
|
/* Кодер видеотрека звонка; только video worker, без камеры, транспорта и таймеров.
|
||||||
* Смена bitrate ожидает ближайший IDR (период <= 1с по capture PTS). Новый encoder
|
* Смена bitrate ожидает ближайший IDR (период <= 1с по capture PTS). Новый encoder
|
||||||
* получает поток после полного drain старого; completion выдаётся после проверки нового IDR. Выбирается GPU;
|
* получает поток после полного drain старого; completion выдаётся после проверки нового IDR. Приоритет GPU, затем CPU;
|
||||||
* явный backend позволяет отдельно проверять software в тестах. Completion передаётся в uasync
|
* явный backend фиксирует выбор для теста/замены. Completion передаётся в uasync
|
||||||
* независимо от admission видео. PTS, generation и frame_id принадлежат владельцу.
|
* независимо от admission видео. PTS, generation и frame_id принадлежат владельцу.
|
||||||
* open получает согласованный call_video_format; соответствие level/размера/FPS
|
* open получает согласованный call_video_format; соответствие level/размера/FPS
|
||||||
* проверяет общий модуль, фактический bitstream — LiveVideoEncoder. CAPS проверяет владелец. */
|
* проверяет общий модуль, фактический bitstream — LiveVideoEncoder. CAPS проверяет владелец. */
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ bool LiveVideoEncoder::open(const LiveVideoConfig& config, Backend backend) {
|
|||||||
c->bit_rate = config.bitrate; c->rc_max_rate = config.bitrate;
|
c->bit_rate = config.bitrate; c->rc_max_rate = config.bitrate;
|
||||||
if (config.maxQp >= 0) { c->qmin = 0; c->qmax = config.maxQp; }
|
if (config.maxQp >= 0) { c->qmin = 0; c->qmax = config.maxQp; }
|
||||||
c->rc_buffer_size = config.vbvBits ? config.vbvBits : config.bitrate / 4;
|
c->rc_buffer_size = config.vbvBits ? config.vbvBits : config.bitrate / 4;
|
||||||
c->gop_size = config.fps; c->max_b_frames = 0; c->thread_count = 2;
|
c->gop_size = config.fps; c->max_b_frames = 0; c->thread_count = 4;
|
||||||
if (config.references) c->refs = config.references;
|
if (config.references) c->refs = config.references;
|
||||||
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER | AV_CODEC_FLAG_CLOSED_GOP;
|
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER | AV_CODEC_FLAG_CLOSED_GOP;
|
||||||
if (constrained) {
|
if (constrained) {
|
||||||
@@ -195,14 +195,12 @@ bool LiveVideoEncoder::open(const LiveVideoConfig& config, Backend backend) {
|
|||||||
if (name == "libx264" || name == "libx265") {
|
if (name == "libx264" || name == "libx265") {
|
||||||
av_dict_set(&options, "preset", "ultrafast", 0); av_dict_set(&options, "tune", "zerolatency", 0);
|
av_dict_set(&options, "preset", "ultrafast", 0); av_dict_set(&options, "tune", "zerolatency", 0);
|
||||||
av_dict_set(&options, "forced-idr", "1", 0);
|
av_dict_set(&options, "forced-idr", "1", 0);
|
||||||
const int workers = std::clamp(av_cpu_count(), 1, 4);
|
const int workers = 4;
|
||||||
QByteArray params = name == "libx264" ? "scenecut=0:open-gop=0:repeat-headers=0"
|
QByteArray params = name == "libx264" ? "threads=4:sliced-threads=1:scenecut=0:open-gop=0:repeat-headers=0"
|
||||||
: "bframes=0:rc-lookahead=0:open-gop=0:frame-threads=1:wpp=1:log-level=error:pools=" + QByteArray::number(workers);
|
: "bframes=0:rc-lookahead=0:open-gop=0:frame-threads=1:wpp=1:log-level=error:pools=" + QByteArray::number(workers);
|
||||||
if (name == "libx265")
|
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "live CPU parallelism encoder=%s workers=%d mode=%s cpu_count=%d",
|
||||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "live HEVC parallelism workers=%d frame_threads=1 wpp=1 cpu_count=%d",
|
name.constData(), workers, name == "libx264" ? "sliced" : "wpp/frame-threads=1", av_cpu_count());
|
||||||
workers, av_cpu_count());
|
|
||||||
if (constrained) {
|
if (constrained) {
|
||||||
c->thread_count = 1;
|
|
||||||
av_dict_set(&options, "profile", name == "libx264" ? "baseline" : "main", 0);
|
av_dict_set(&options, "profile", name == "libx264" ? "baseline" : "main", 0);
|
||||||
// Оба encoder принимают level × 10 целым: дробный разбор зависит от LC_NUMERIC.
|
// Оба encoder принимают level × 10 целым: дробный разбор зависит от LC_NUMERIC.
|
||||||
QByteArray level = QByteArray::number(name == "libx264" ? config.level : config.level / 3);
|
QByteArray level = QByteArray::number(name == "libx264" ? config.level : config.level / 3);
|
||||||
@@ -360,9 +358,10 @@ bool LiveVideoEncoder::open(const LiveVideoConfig& config, Backend backend) {
|
|||||||
}
|
}
|
||||||
DEBUG_INFO(DEBUG_CATEGORY_VIDEO,
|
DEBUG_INFO(DEBUG_CATEGORY_VIDEO,
|
||||||
"desktop encoder ready name=%s codec=%d size=%dx%d fps=%d bitrate=%d level=%d refs=%d vbv=%d profile_verified=%d "
|
"desktop encoder ready name=%s codec=%d size=%dx%d fps=%d bitrate=%d level=%d refs=%d vbv=%d profile_verified=%d "
|
||||||
"forced_keys=%d max_qp=%d dynamic_qp=%d",
|
"forced_keys=%d max_qp=%d dynamic_qp=%d threads=%d thread_type=%d",
|
||||||
name.constData(), config.codec, config.width, config.height, config.fps, config.bitrate,
|
name.constData(), config.codec, config.width, config.height, config.fps, config.bitrate,
|
||||||
config.level, config.references, c->rc_buffer_size, constrained, m->forcedKeys, config.maxQp, canSetMaxQp());
|
config.level, config.references, c->rc_buffer_size, constrained, m->forcedKeys, config.maxQp, canSetMaxQp(),
|
||||||
|
c->thread_count, c->active_thread_type);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user