366 lines
38 KiB
Plaintext
366 lines
38 KiB
Plaintext
Видеозвонки Android и ChatGUI
|
||
|
||
Контракт
|
||
Каждая сторона независимо включает видео. Автовыбор H.265 Main 8-bit, затем
|
||
H.264 Constrained Baseline: пересечение encoder отправителя и decoder получателя.
|
||
Камера, разрешение, кодек и диапазон битрейта меняются во время звонка.
|
||
Автоматический диапазон по умолчанию 300–4000 кбит/с (десятичные единицы).
|
||
|
||
Время
|
||
Общая монотонная шкала захвата аудио и видео на каждом отправителе. PTS первого
|
||
аудиосэмпла/кадра сохраняется до вывода; время сетевой отправки учитывается отдельно.
|
||
Приёмное видео следует исходной позиции реально воспроизводимого аудио, включая
|
||
SoundTouch и очередь устройства. Алгоритм регулирования аудиобуфера сохраняется.
|
||
Искусственная тишина/тоны не продвигают исходную позицию. Формат видео меняется по PTS;
|
||
новое поколение не уничтожает старые кадры, соответствующие ещё не прозвучавшей речи.
|
||
|
||
Передача и регулирование
|
||
Один A/V-планировщик, независимые логические каналы управления/аудио/видео.
|
||
Звук продолжает работу при отказе камеры. Ограничены ожидание encode, очереди,
|
||
размер сборки кадра и память получателя; ACK не равен успешному decode/render.
|
||
Роутер считает исходный payload и пакеты, видеомодуль вычитает фиксированный
|
||
заголовок фрагмента. Физические очереди повторно не суммируются с router inflight.
|
||
Окно ACK: 10 завершённых интервалов по 50мс, текущая ячейка отдельно.
|
||
Регулятор общий C, решения проверяются управляемым временем. Снижение учитывает
|
||
подтверждённую скорость и разгрузку задолженности; повышение — малыми пробами.
|
||
Нет отдельного неограниченного интегратора: задолженность уже интегрирует дефицит.
|
||
Учитываются прогрев, RTT, minrtt_probe, отсутствие маршрута, локальное удержание
|
||
планировщиком, применение encoder-команды и смена эпохи.
|
||
|
||
Владение
|
||
Состояние звонка/регулятора/роутера — uasync. Камера и encoder/decoder — платформенные
|
||
workers. Ограниченный mailbox, одно ожидающее уведомление. Команды bitrate имеют
|
||
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; см. ниже.
|
||
[+] ChatGUI codec component: замена H.264/H.265 encoder на IDR, с непрерывными PTS; ещё без camera/bridge.
|
||
[ ] Android MediaCodec: применение bitrate на ближайшем IDR и проверка фактического выхода.
|
||
[+] Общий регулятор с детерминированными сценариями и подключением к router/encoder-командам.
|
||
[+] Видеофрагменты, ограниченная сборка, обмен возможностями с подтверждением.
|
||
[ ] Дополнить возможности ограничениями profile/level/tier и диапазоном битрейта.
|
||
[ ] Завершить A/V scheduler с платформенными очередями захвата/encode.
|
||
[+] Общие capture PTS и отображение позиции аудиоустройства в исходное время.
|
||
[ ] ChatGUI: движок, окно и настройки; Android: движок, JNI, сервис и экран.
|
||
[ ] Интеграционные проверки всех пар, перегрузки, смены формата и lifecycle.
|
||
|
||
Приёмка
|
||
Нет двойного учёта байтов: принято = подтверждено + отменено + задолженность.
|
||
Повторные ACK/передачи не увеличивают delivered. Reset не считается доставкой.
|
||
Свободный канал не вызывает снижение на статичной сцене; рост полосы обнаруживается
|
||
пробами. Очереди остаются ограниченными при отсутствии ACK и остановке decoder.
|
||
Видео следует аудио при догоне, underrun, смене устройства и формате видеотрека.
|
||
Завершение звонка безопасно во время переключения камеры, bitrate и decoder.
|
||
|
||
Проверка SoundTouch, 14.10.2026
|
||
test_soundtouch_clock сравнивает положение реальных четырёхсэмпловых фрагментов
|
||
в выходном сигнале с двумя вариантами временной шкалы. 60с входа, mono 48kHz,
|
||
sequence=20ms, seek=10ms, overlap=4ms — параметры существующего call_jitter.
|
||
Максимальная ошибка feed/tempo / consumed-input, мс:
|
||
постоянный темп 1.6: 14.208 / 14.271
|
||
плавный цикл 1.0..1.6 (шаг 0.012/20ms): 29.550 / 13.723
|
||
стресс, переключение 1.0/1.6 каждые 20ms: 938.104 / 14.462
|
||
Стресс не воспроизводит ограничение темпа звонка, а проверяет отсутствие накопления.
|
||
Проблема: setTempo меняет обработку ещё не потреблённого входа; номинальные интервалы
|
||
frames/tempo, записанные при feed, не описывают фактический выход. Поэтому копировать
|
||
этот способ из stream_playback_audio в звонки нельзя. Изменений звука/буфера нет.
|
||
|
||
Рассмотренные варианты (реализован вариант 2):
|
||
1. Минимальный: шкала по фактически потреблённому входу и произведённому выходу,
|
||
с поправкой на seek-window. Тест показал <15мс на трёх сценариях, но это ещё не
|
||
доказанная граница для речи/Opus/разных блоков. Нужны эти проверки и явный допуск.
|
||
2. Более строгий: SoundTouch публикует соответствие исходных участков выходным
|
||
непосредственно в TDStretch. Позволяет учитывать выбранный WSOLA offset без
|
||
вычисления по косвенным счётчикам; потребует небольшого расширения bundled API.
|
||
Overlap смешивает два участка, поэтому даже здесь нужно определить правило PTS.
|
||
Рекомендуется для общего A/V clock: не меняет звук, исключает накопительный дрейф.
|
||
Реализованная шкала
|
||
SoundTouch сообщает Copy/Mix с фактическими индексами входа/выхода после WSOLA.
|
||
Mix интерполирует PTS двумя теми же линейными весами, которыми смешивается PCM.
|
||
Это определение времени смешанного сигнала, а не утверждение, что у смеси один источник.
|
||
Поддержан профиль звонка: float PCM, mono/stereo, rate=pitch=1, AA выключен.
|
||
Неподдержанная смена профиля/flush отключает карту до reset, сохраняя обработку звука.
|
||
CallTimeline переносит участки через частичные receiveSamples и локальные тоны/тишину.
|
||
Кольца ограничены; переполнение или противоречивый progress запрещают valid до reset.
|
||
Краткое движение исходного PTS назад удерживается, held_back_us видно в диагностике.
|
||
Разрыв более 100мс и смешивание разных source_epoch не дают valid-PTS.
|
||
|
||
Аудиопакет несёт capture_pts_us, capture_epoch и codec_delay_samples (Opus lookahead).
|
||
Метка неизвестного источника — INT64_MIN. Старого формата протокола больше нет.
|
||
После разрыва захвата хвост прежнего Opus не получает вымышленную новую метку.
|
||
Desktop передаёт исходную метку callback захвата; playback использует позицию PCM
|
||
и время вывода backend. measured показывает аппаратную отметку либо оценку backend.
|
||
Android использует AudioRecord timestamp MONOTONIC; до появления timestamp оценка
|
||
привязана один раз к окончанию первого read и далее идёт по сэмплам. После исчезновения
|
||
timestamp продолжается последний якорь. Это ограничение точности, а не аппаратное измерение.
|
||
AudioTrack playbackHeadPosition разворачивается из unsigned32 и ограничивается реально
|
||
записанным PCM. Опрос head — estimated (measured=0), write не подтверждает воспроизведение.
|
||
Локальные часы API — MONOTONIC, не get_time_us ядра (на Linux он использует BOOTTIME).
|
||
Снимок без progress более 250мс недостоверен; экстраполяции за подтверждённый участок нет.
|
||
Логи call DEBUG показывают epoch/source/played/written/PTS/valid/measured/held раз в секунду.
|
||
Видеотранспорт подключён к ядру; codecs, полный scheduler и UI ещё не подключены. Проверка A/V на устройствах
|
||
остаётся следующим интеграционным этапом; unit-тесты не измеряют физическую задержку динамика.
|
||
|
||
Проверки текущего этапа
|
||
./build.sh --no-gui -j4 — успешно.
|
||
./check.sh — 153/153, proxy 9/9, burst и load успешно; /tmp/call-video-check.log.
|
||
test_etcp_router_unit — 36/36; /tmp/call-video-router-unit.log.
|
||
UDP и STCP — по 440 пакетов, 5 циклов backpressure, без потерь/дублей/повреждений;
|
||
/tmp/call-video-router-udp.log, /tmp/call-video-router-tcp.log.
|
||
Регулятор: модель 120с с полосой 1.5→3Mbps, max debt=118559 bytes;
|
||
статичная сцена — 0 ложных снижений. Pending, cap, no route, warmup, локальное
|
||
удержание, minrtt probe, RTT=600ms проверены. Интеграция encoder ещё отсутствует.
|
||
test_soundtouch_clock — три сценария проходят предел consumed-input <20ms;
|
||
этот предел теста не является гарантией для всех входных сигналов.
|
||
|
||
Проверки реализованного варианта 2
|
||
Сравнение SoundTouch с callback и без него: PCM побитно одинаков; Copy/Mix
|
||
восстанавливаются по фактическому входу, включая mono/stereo, partial read и clear.
|
||
CallTimeline: 200с реального SoundTouch, смена темпа, границы участков, переполнение,
|
||
неверная/устаревшая позиция устройства и восстановление через reset.
|
||
CallAudio: 40с реального Opus+jitter, burst/догон, тоны/тишина, эпоха устройства;
|
||
capture metadata проверены через очередь uasync и реальный сетевой звонок.
|
||
Desktop: шесть профильных + пять проверок общего аудиостека прошли, vibechat собран.
|
||
Android: assembleDebug и все 79 unit-тестов прошли (arm64-v8a и x86_64 native).
|
||
./check.sh: 153/153, proxy 9/9, burst/load PASS; /tmp/call-clock-check-final.log.
|
||
Логи: /tmp/call-clock-desktop-final-tests.log, /tmp/call-clock-shared-tests.log
|
||
(test_radio_member_mute повторён вне sandbox: /tmp/call-clock-radio-mute-test.log),
|
||
/tmp/call-clock-android-final.log. Физические устройства в этом этапе не проверялись.
|
||
|
||
Реализованный видеотранспорт, 14.10.2026
|
||
call_video.c задаёт общий wire и сборку; call_video_transport.c владеет состоянием
|
||
видеоканала внутри call_session. Сигнализация звонка, video control, audio и video
|
||
имеют отдельные router service IDs. Приёмная очередь видео не блокирует аудио.
|
||
CAPS повторяется до прикладного CAPS_ACK: получение транспортного ACK не гарантирует,
|
||
что получатель уже обработал ACCEPT и установил capabilities. Кодек выбирается
|
||
направленно: encoder отправителя пересекается с decoder получателя, H.265 перед H.264.
|
||
Текущие limits проверяют размеры, FPS и pixels/second; контракт профиля ещё неполон.
|
||
|
||
Заголовок фрагмента 52 байта, payload до 1200 байт; полный кадр до 2MiB.
|
||
KEY содержит config_length:4BE + AnnexB config + access unit. Ядро проверяет
|
||
границы envelope; содержимое NAL обязан проверять платформенный decoder.
|
||
frame_id и capture PTS возрастают на всём протяжении звонка, включая смену generation.
|
||
Новый формат требует нового generation и KEY. После пропуска кадра нужен KEY.
|
||
На TX один незавершённый кадр, на RX одна ограниченная сборка; deadline 2с.
|
||
receive_ready резервирует возможность принять целый кадр до ACK первого фрагмента.
|
||
Callback копирует данные до возврата; платформенная очередь также должна быть ограничена.
|
||
Старые кадры другого generation сохраняются до соответствующей позиции аудиоряда.
|
||
|
||
Видео пока удерживается до передачи соответствующего аудио в router. Аудио никогда
|
||
не ждёт камеру. Это первая часть scheduler: ограничение ожидания encode, pacing
|
||
на максимальном битрейте и политика остановки видеотрека остаются следующими задачами.
|
||
flush ограничен 16 фрагментами за вызов; пропускную способность этого бюджета нужно
|
||
проверить вместе с частотой вызовов от платформенного producer и аудио.
|
||
|
||
Регулятор получает endpoint ACK 500мс/50мс и queued+inflight отдельного видеосервиса.
|
||
Фиксированные заголовки вычитаются; добавляется ещё не переданный остаток кадра.
|
||
Удержание по аудио не трактуется как нехватка сети. Смена эпохи сбрасывает окно.
|
||
Ограничение admission: задолженность + новый кадр не превышают 2MiB.
|
||
Одна команда bitrate в работе, подтверждение проверяет generation/request;
|
||
устаревшее подтверждение отвергается. Timeout 2с или отказ encoder останавливает
|
||
admission до явной повторной настройки; аудиозвонок продолжает работу.
|
||
Платформенные callbacks вызываются в uasync и не меняют call API реентерабельно.
|
||
При hangup отменяются таймеры и освобождаются pending TX/RX, callbacks снимаются.
|
||
|
||
Проверки видеотранспорта
|
||
./check.sh: 154/154, proxy 9/9, burst/load PASS; /tmp/call-video-core-check.log.
|
||
test_call_video проверяет capabilities, wire, фрагментацию, replay, разрыв,
|
||
timeout, смену generation и некорректные размеры/config.
|
||
test_call через два реальных UDP-ядра проверяет обмен CAPS, удержание видео по аудио,
|
||
backpressure получателя без остановки аудио, H.265 -> H.264 с новым generation,
|
||
bitrate command/ACK, устаревшие ACK и hangup с ожидающим кадром.
|
||
Payload в этом тесте синтетический: тест не доказывает работу HEVC/AVC decoder.
|
||
Лог: /tmp/call-video-rate-integration.log.
|
||
ChatGUI vibechat собран; test_voice_tx и test_call_jitter прошли.
|
||
Android assembleDebug/testDebugUnitTest успешны; /tmp/call-video-android-core-build.log.
|
||
Камера, декодирование/показ и физическая A/V-синхронизация пока не проверены.
|
||
|
||
Выявленная нестыковка перед подключением codecs
|
||
Размеров/FPS/pixels-per-second недостаточно: допустимый битрейт зависит также от
|
||
profile/level/tier и ограничений конкретного decoder. Текущий StreamVideoEncoder
|
||
не умеет runtime bitrate для H.265, а прямой x265 требует дополнительной проверки.
|
||
В upstream x265_encoder_reconfig при смене profile/level/tier отменяет изменение
|
||
rate-control, но эта ветка не меняет ret=0. Успешный return не доказывает применение.
|
||
Источник: https://github.com/videolan/x265/blob/master/source/encoder/api.cpp
|
||
|
||
Предлагаемое продолжение:
|
||
1. Зафиксировать Main 8-bit / Constrained Baseline и согласовать level/tier,
|
||
верхний bitrate/VBV и ограничения reference frames для каждого направления.
|
||
Выбранный режим должен проверяться фактическим открытием encoder/decoder.
|
||
2. Открывать encoder в согласованных пределах. Автоадаптация работает внутри них
|
||
без пересоздания. ACK команды означает проверенное фактическое применение,
|
||
а не только возврат setter; отдельно измеряется реальный выход encoder.
|
||
3. Пользовательское изменение за пределами режима создаёт новый generation,
|
||
config и KEY после проверки возможностей получателя; звук продолжается.
|
||
4. Проверить установленный x265 и Android MediaCodec тестом encode/decode с
|
||
понижением/повышением битрейта и отказом настройки. Непригодный H.265 backend
|
||
не объявляется доступным; в auto используется H.264.
|
||
Подключение платформенных codecs остановлено на этой границе согласно AGENTS.md.
|
||
|
||
Настройка диапазона, 14.10.2026
|
||
ChatGUI: Настройки -> аудио, поля минимального/максимального битрейта видеозвонка.
|
||
Android: Настройки -> аудио, ползунок диапазона. По умолчанию 300–4000 кбит/с;
|
||
пользователь может сузить диапазон внутри этих границ, включая фиксированный bitrate.
|
||
Одна атомарная настройка call_video_bitrate_range_kbps=300:4000 хранится в конфиге
|
||
desktop / DataStore Android и передаётся в общий chat_setting. min > max отвергается
|
||
без частичного изменения. Android включает настройку в конфиг при каждом запуске.
|
||
Во время звонка transport читает диапазон каждые 50мс, не сбрасывая pending-команду.
|
||
Верхняя граница ограничена проверенным codec cap текущего generation. Если новый
|
||
минимум выше codec cap, admission приостановлен до совместимой настройки/режима;
|
||
это событие логируется. Смена диапазона сама по себе не расширяет возможности codec.
|
||
При сети слабее 300 кбит/с target не уходит ниже нижней границы; bounded admission
|
||
не позволяет очереди бесконечно расти. Аудиоканал продолжает работать отдельно.
|
||
Порог 5% при снижении не мешает достигнуть точной нижней границы диапазона.
|
||
|
||
Проверено: модель полосы 150 кбит/с -> 6 Мбит/с достигает target 300 кбит/с,
|
||
затем 4 Мбит/с, очередь остаётся ограниченной. Сетевой test_call меняет диапазон
|
||
при pending-команде, принимает прежний ACK и затем получает target нового диапазона;
|
||
также проверяет отказ несовместимого codec cap. Логи /tmp/call-range-rate-test.log
|
||
и /tmp/call-range-integration-test.log. ChatGUI собран; Android assembleDebug и
|
||
81 unit-тест прошли, /tmp/call-range-android-ui-final.log.
|
||
Полный ./check.sh вне sandbox: 154/154, proxy 9/9, burst/load PASS;
|
||
/tmp/call-range-check-final.log. Первый запуск в sandbox блокировался запретом сокетов.
|
||
Настройки и регулятор готовы; подключение камеры/codec/render остаётся отдельным этапом.
|
||
|
||
Проверка реального x265 перед подключением backend, 14.10.2026
|
||
Добавлена ручная цель probe_call_x265 (EXCLUDE_FROM_ALL, не входит в ctest), если
|
||
найден x265 через pkg-config. Сборка/запуск:
|
||
cmake --build tools/chatgui/build --target probe_call_x265 -j4
|
||
./tools/chatgui/build/probe_call_x265
|
||
./tools/chatgui/build/probe_call_x265 --frame-rc
|
||
Один encoder, 640x360@30, Main 8-bit/Main tier/level 3.1, reference=1,
|
||
B=0/lookahead=0, ABR+VBV, буфер 1000 кбит. Три участка по 120 кадров:
|
||
4 Мбит/с -> 300 кбит/с -> 4 Мбит/с. Детерминированная шумовая сцена требует полосы;
|
||
измерение каждого участка исключает первые 30 кадров переходного процесса.
|
||
Код 0 — измерение прошло; 1 — ошибка API/потеря PTS; 2 — непригодный rate control.
|
||
Допуск измерения 0.5..1.5 target — диагностический, не гарантия CBR для любой сцены.
|
||
|
||
Установленная библиотека 4.1+1-1d117be (пакет 4.1-4) не проходит пробу:
|
||
target 4000000: output 4016866 бит/с;
|
||
target 300000: output 4006669 бит/с, несмотря на getter bitrate=300/vbv=300 кбит/с;
|
||
target 4000000: output 3945016 бит/с.
|
||
Лог: /tmp/call-x265-system.log. Return reconfigure=0 и getter недостаточны.
|
||
frame-rc также непригоден для этого zerolatency-профиля: output около 40 кбит/с
|
||
на всех трёх участках; /tmp/call-x265-frame-rc.log.
|
||
|
||
Причина проверена по исходникам именно установленного выпуска:
|
||
https://deb.debian.org/debian/pool/main/x/x265/x265_4.1.orig.tar.xz
|
||
SHA256 85abb8a850000bf693947459c42a666a3ecd6de10a2ac6b3c6647554b14d3270
|
||
Encoder::configure(p) теперь присваивает this->m_param=p. Вызов из
|
||
x265_encoder_reconfig с m_latestParam переключает encoder на новый объект, но
|
||
RateControl::m_param остаётся прежним адресом. Последующий x265_copy_params
|
||
копирует latest в него самого; reconfigureRC читает старые параметры rate control.
|
||
Для frame-rc обнаружен отдельный дефект: tuneQscaleToUpdatedBitrate делит
|
||
frameBitsTotal на i=0 при пустом lookahead, что в этой пробе приводит к QP=69.
|
||
|
||
Проверенный минимальный патч сохраняет активный m_param до configure(latest)
|
||
и восстанавливает его после. Файл для дальнейшего подключения:
|
||
tools/chatgui/ffmpeg/patches/x265-4.1-reconfigure-param-owner.patch
|
||
Применён только к отдельной копии исходников в /tmp/call-x265-source;
|
||
библиотека собрана в /tmp/call-x265-build без установки в систему.
|
||
С тем же тестом и frame-rc=off output=4016866 / 298165 / 4213269 бит/с.
|
||
Логи: /tmp/call_x265_probe_fixed.log и /tmp/call-x265-fixed.log.
|
||
Дополнительная проверка ffprobe: 360/360 кадров декодируются, Main, level=93
|
||
(HEVC level 3.1), has_b_frames=0. Системная библиотека и приложение не заменены.
|
||
ChatGUI успешно собирается; /tmp/call-x265-desktop-build.log.
|
||
|
||
Первоначальное предложение (заменено решением переключать 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 остаётся диагностическим материалом и не требуется выбранному способу.
|
||
|
||
Компонент кодирования ChatGUI, 14.10.2026
|
||
StreamVideoEncoder переименован в LiveVideoEncoder и выделен в chatgui_live_video;
|
||
трансляции используют тот же код, без дублирования захвата/конвертации/FFmpeg.
|
||
Явный профиль H.264 Constrained Baseline / H.265 Main задаёт level, reference=1,
|
||
VBV и 8-bit 4:2:0. Для этого режима пока проверены software libx264/libx265.
|
||
Открытие проверяет независимый IDR настоящим decoder: profile, level, Main tier,
|
||
pixel format, отсутствие B-кадров и размер. Проверка принятого option не заменяет
|
||
эту проверку bitstream. Automatic-профили трансляций сохраняют прежний выбор GPU/SW.
|
||
Опции encoder сверены с https://ffmpeg.org/ffmpeg-codecs.html#libx265 и разделом libx264.
|
||
|
||
CallVideoEncoder принадлежит будущему video worker. Он хранит единственную pending
|
||
команду generation/request/bitrate, отклоняет replay, чужой generation и выход за
|
||
согласованный maximumBitrate. На ближайшем IDR по capture PTS создаётся кандидат;
|
||
старый encoder сохраняется до получения полного KEY с точным исходным PTS.
|
||
При отказе кандидата возвращается completion с bitrate=0 и используется прежний
|
||
контекст. Неизменный target также подтверждается на KEY без пересоздания.
|
||
Completion отделён от отправки кадра: даже при закрытом admission его нужно
|
||
передать в call_video_rate_applied. Периодический IDR задаётся по capture PTS,
|
||
поэтому пропуски кадров/закрытая сеть не сдвигают применение на дополнительные GOP.
|
||
Физический захват камеры, audio origin и сетевые frame_id компонентом не меняются.
|
||
|
||
test_call_video_encoder прошёл: 5 QtTest cases (включая init/cleanup), без skip.
|
||
Для обоих codecs: 640x360@30, level 3.1, VBV 1 Мбит, шумовая сцена;
|
||
запрос на кадре 7, переход на кадре 30, один decoder на все 360 кадров.
|
||
Проверены PTS каждого decoded frame, профиль/level/размер/B=0 и средний bitrate:
|
||
H.264: 3996916 / 296904 / 3989748 бит/с;
|
||
H.265: 3993720 / 302956 / 3999788 бит/с.
|
||
Отдельно проверены отказ новой конфигурации с сохранением старого encoder,
|
||
предел bitrate, pending/replay/generation, force-key и разрыв capture PTS вперёд.
|
||
Логи: /tmp/call-live-video-test-final.log, /tmp/call-live-video-build-final.log.
|
||
test_stream_publish: 11 passed, 1 skip (capture под Xvfb), 0 failed;
|
||
/tmp/call-live-stream-regression.log. После уточнения VBV профильная проверка
|
||
liveSoftwareBitrateKeepsDecoder повторена успешно, /tmp/call-live-stream-bitrate-final.log.
|
||
ChatGUI собран; ./check.sh: 154/154, proxy 9/9, burst/load PASS за 118с;
|
||
/tmp/call-live-core-check.log. Android в этом этапе не менялся.
|
||
|
||
Граница готовности: это рабочий codec component, ещё не камера/worker/видеозвонок.
|
||
В CAPS пока нет согласования level/tier/bitrate/VBV: до его реализации компонент
|
||
не объявляется доступным в реальном звонке. Владелец обязан проверять соответствие
|
||
размера/FPS согласованному envelope, а не считать маркировку level доказательством
|
||
всех ограничений стандарта. Другие режимы, hardware codecs и Android требуют
|
||
отдельных проверок. Следующий этап — CAPS envelope и подключение capture/bridge,
|
||
затем decoder/render по audio clock и UI на обеих платформах.
|