Browse Source

Specify deferred bitrate changes and validate IDR before releasing old encoder

master
evgeny 4 days ago
parent
commit
f89494fb4f
  1. 49
      doc/call_video.txt
  2. 5
      doc/tasks.md
  3. 12
      tools/chatgui/tests/probe_call_x265.cpp

49
doc/call_video.txt

@ -34,11 +34,35 @@ call_id, video_generation и request_id; одно исполнение и пос
Принятая настройка не заменяет измерение фактического выхода. Shutdown отменяет
уведомления/таймеры, останавливает producers, затем освобождает очереди и codecs.
Применение bitrate на ключевом кадре (уточнение пользователя)
Worker хранит pending-команду и применяет её перед кодированием ближайшего
планового IDR. GOP ограничен одной секундой исходной шкалы capture PTS, а не
числом принятых сетью кадров: backpressure не должен блокировать переключение.
Для x265 используется новый encoder с нужным bitrate; обычный reconfigure даже
на IDR не обходит найденный дефект 4.1. Исправленная внешняя библиотека не нужна.
Первый выход нового encoder обязан содержать IDR и актуальные VPS/SPS/PPS.
Камера, audio epoch, capture PTS и последовательность frame_id не перезапускаются.
При неизменном формате bitrate не меняет video_generation; новые parameter sets
идут с KEY. Смена codec/разрешения/камеры сохраняет отдельный протокол generation.
Приём применяет конфигурацию перед декодированием соответствующего KEY, не удаляя
уже декодированные старые кадры, ожидающие своего времени по audio clock.
Подтверждение rate_applied отправляется после проверки первого нового IDR,
независимо от сетевого admission; иначе закрытый admission создаст взаимное ожидание.
Успех означает применение настройки, не гарантию бит-в-бит постоянного выхода.
До IDR регулятор видит старый applied bitrate и одну pending-команду; его текущий
таймаут 2с включает ожидание IDR и открытие encoder. При отсутствии кадров/ошибке
команда завершается отказом; нельзя бесконечно продлевать её таймаут.
Ограничитель очереди работает и во время ожидания. Если новый IDR не принят,
producer запрашивает следующий IDR по существующему контракту send_frame.
Открытие кандидата и проверка первого IDR предшествуют освобождению старого encoder;
ошибка не должна уничтожать рабочий контекст. Реальные затраты переключения и
пиковый объём IDR нужно проверить для каждого доступного режима/backend.
Порядок реализации
[+] История первых ACK 500мс/50мс и снимок payload send_q/inflight отдельного сервиса.
[+] Unit счётчиков: повторные ACK, reset, отдельные сервисы; UDP/STCP регрессии пройдены.
[+] Дрейф feed/tempo устранён картой фактических участков SoundTouch; см. ниже.
[ ] H.265 runtime bitrate: поддерживаемый backend без циклического пересоздания.
[ ] H.265 bitrate: замена encoder перед ближайшим плановым IDR, с непрерывными PTS.
[+] Общий регулятор с детерминированными сценариями и подключением к router/encoder-командам.
[+] Видеофрагменты, ограниченная сборка, обмен возможностями с подтверждением.
[ ] Дополнить возможности ограничениями profile/level/tier и диапазоном битрейта.
@ -267,9 +291,30 @@ frameBitsTotal на i=0 при пустом lookahead, что в этой про
(HEVC level 3.1), has_b_frames=0. Системная библиотека и приложение не заменены.
ChatGUI успешно собирается; /tmp/call-x265-desktop-build.log.
Рекомендуемое продолжение: закрепить проверенную версию x265 и патч в локальной
Первоначальное предложение (заменено решением переключать encoder на IDR ниже):
закрепить проверенную версию x265 и патч в локальной
сборке зависимости, повторить codec-пробу для рабочих разрешений и decoder,
затем подключить direct API к backend звонка. Непрошедший проверку backend
не объявлять в capabilities; H.264 остаётся альтернативой, когда H.265 недоступен.
Патч пока не подключён к build_ffmpeg.sh; изменение поставки зависимости и
интеграция backend остановлены по правилу AGENTS.md о выявленной нестыковке.
Проверка переключения на плановом IDR, 14.10.2026
По уточнению пользователя вместо поставки изменённой x265 проверено пересоздание
encoder на очередном IDR. Добавлены режимы probe_call_x265:
--keyframe-reconfig
--keyframe-reopen --output /tmp/call-x265-key-reopen.hevc
Запрос приходит на кадре 7 очередного участка; применение перед кадром 30,
через 23 кадра (767мс при 30fps). Плановый IDR задаётся каждые 30 кадров,
проверяются его NAL-тип и наличие VPS/SPS/PPS. PTS всех 360 кадров проверяются
на точное соответствие исходным, включая обе границы замены encoder.
Измеряются последние 60 кадров каждого 120-кадрового участка, после перехода.
На системной x265 4.1 без патча:
reconfigure перед IDR: 4008828 / 4001940 / 3977828 бит/с — отказ, код 2;
новый encoder на IDR: 4008828 / 309564 / 4019812 бит/с — PASS, код 0.
Логи: /tmp/call-x265-key-reconfig.log, /tmp/call-x265-key-reopen.log.
ffmpeg -v error -xerror декодирует объединённый поток без ошибок;
ffprobe подтверждает Main/level 3.1, B=0 и 360 кадров.
Это проверка 640x360@30 на синтетической сложной сцене, не готовый тракт звонка:
worker/camera/decoder UI и Android MediaCodec ещё предстоит подключить и проверить.
Патч x265 остаётся диагностическим материалом и не требуется выбранному способу.

5
doc/tasks.md

@ -26,7 +26,10 @@
Минимальный патч владения параметрами проверен на отдельной библиотеке в /tmp:
реальный выход 4.02 -> 0.298 -> 4.21 Мбит/с, декодируются 360/360 кадров.
Патч сохранён в tools/chatgui/ffmpeg/patches, к сборке/приложению пока не подключён.
Согласно AGENTS.md остановлено перед изменением зависимости; подробности и варианты в плане.
Пользователь выбрал переключение на ближайшем плановом IDR: проверено пересоздание x265 без патча,
4.01 -> 0.310 -> 4.02 Мбит/с, 360/360 кадров декодируются с сохранёнными PTS кодера.
Обычный reconfigure на IDR не помогает. В плане уточнены ожидание <= одного GOP, pending ACK,
backpressure и сохранение аудиошкалы; подключение к платформенным workers ещё предстоит.
Контракты, этапы и проверки: `doc/call_video.txt`.
[+] **Android live: увеличение и перемещение видео как в просмотрщике файлов** — 14.10.2026:

12
tools/chatgui/tests/probe_call_x265.cpp

@ -1,4 +1,4 @@
/* Диагностика пригодности x265 для звонка: один encoder, 4M -> 300k -> 4M,
/* Диагностика пригодности x265 для звонка: reconfigure или замена на IDR, 4M -> 300k -> 4M,
* фиксированный Main 8-bit / Main tier / level 3.1, без lookahead/B-кадров.
* Проверяем фактический выход, а не только return/getter reconfigure.
* Запускается вручную; код 2 означает, что backend не прошёл пробу адаптации. */
@ -12,11 +12,12 @@
struct Probe {
const x265_api* api = nullptr;
x265_param *parameters = nullptr, *actual = nullptr;
x265_encoder* encoder = nullptr;
x265_encoder *encoder = nullptr, *previous = nullptr;
FILE* dump = nullptr;
~Probe() {
if (dump && fclose(dump)) DEBUG_ERROR(DEBUG_CATEGORY_CALL, "x265 probe output close failed");
if (encoder) api->encoder_close(encoder);
if (previous) api->encoder_close(previous);
if (parameters) api->param_free(parameters);
if (actual) api->param_free(actual);
}
@ -91,7 +92,7 @@ int main(int argc, char** argv) {
if (keyReopen) {
x265_encoder* candidate = p.api->encoder_open(config);
if (!candidate) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "x265 reopen failed phase=%d", phase); return 1; }
p.api->encoder_close(p.encoder); p.encoder = candidate;
p.previous = p.encoder; p.encoder = candidate;
} else {
result = p.api->encoder_reconfig(p.encoder, config);
if (result) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "x265 key reconfig failed phase=%d result=%d", phase, result); return 1; }
@ -130,6 +131,11 @@ int main(int argc, char** argv) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "x265 incomplete IDR phase=%d frame=%d idr=%d vps=%d sps=%d pps=%d",
phase, frame, idr, vps, sps, pps); return 1;
}
if (p.previous) {
p.api->encoder_close(p.previous); p.previous = nullptr;
DEBUG_INFO(DEBUG_CATEGORY_CALL, "x265 replacement committed phase=%d frame=%d pts=%lld idr=%d",
phase, frame, (long long)output.pts, idr);
}
if (frame < 3 || (keyMode && frame == 30)) {
p.api->encoder_parameters(p.encoder, p.actual);
DEBUG_INFO(DEBUG_CATEGORY_CALL, "x265 probe phase=%d frame=%d requested_kbps=%d getter_kbps=%d vbv_kbps=%d level=%d",

Loading…
Cancel
Save