Per-distro distribution plan updated with what the three deployed binaries actually are (XUI 2018 / mardock2009 no-GPU / our glibc-2.35 build), the code-driven target codec set (+nvenc/cuvid/librtmp, -AV1), the 8.1 label decision, and the -nofix_dts custom-flag replacement plan validated via tools/dts-audio-test.
15 KiB
План: per-distro дистрибуция FFmpeg через XC_VM_FFMPEG
Статус: черновик плана (июль 2026). Цель — раздавать ffmpeg/ffprobe на ноды
отдельными сборками под каждый дистрибутив (собранными в контейнере своего
дистро → glibc гарантированно совпадает), фетчить их из релизов
XC_VM_FFMPEG при установке и обновлять кроном — по образцу MaxMind/proxy.
Уходим от одного «forward-compatible» бинаря в Git LFS.
Первопричина. Единый бинарь собирался на Debian 11 (glibc 2.31) в расчёте на
forward-compat. FFmpeg 8.x требует glibc ≥ 2.34 → на Debian 11 / Ubuntu 20.04
(2.31) не стартует: ffprobe: ... version 'GLIBC_2.35' not found. Именно это
уронило воспроизведение фильма на LB2 (Ubuntu 20.04) при ffmpeg_cpu='8.0'.
Оперативный обход на проде — переключить настройку ffmpeg_cpu/ffmpeg_gpu на
7.1 (статический билд, работает на 2.31).
0. Текущее состояние
Репозиторий сборщика — XC_VM_FFMPEG (СДЕЛАНО, запушен):
| Что | Файл | Примечание |
|---|---|---|
Сборщик (перенесён 1:1 из XC_VM_Binaries) |
build_ffmpeg.sh |
все кодеки статически, динамически только glibc; verify_static падает, если остался не-glibc .so. Env: V_FFMPEG, FF_LABEL, FF_DISTRO, OUT_DIR |
| Matrix-драйвер (единый источник матрицы) | build_ffmpeg_all.sh |
(версия × дистро), per-distro image + прогон по версиям; --print-matrix для CI; hashes для md5 |
| Dockerfile под дистро | docker/Dockerfile |
ARG BASE_IMAGE |
| CI | .github/workflows/build-release.yml |
workflow_dispatch → параллельная матрица → draft-релиз + hashes.md5 |
| Прочее | Makefile, versions.json, README.md, RELEASE.md, .gitignore |
Матрица: 4.0/7.1/8.1 × debian_11/12/13, ubuntu_20/22/24 = 18 ассетов
вида ffmpeg_<label>_<distro>.tar.gz + hashes.md5. Rocky_9 — TODO.
Обновление сборщика (в XC_VM_FFMPEG, ещё НЕ закоммичено): набор кодеков
приведён к тому, что реально дёргает код (см. §0a): +nvenc/cuvid/ffnvcodec
(GPU), +librtmp, оставлен fdk-aac; −AV1 (aom/dav1d — не используются).
4.0 теперь пересобирается из ffmpeg 4.4.5 (не бинарь XUI): GPU + нативный
DTS-декод. nv-codec-headers пинятся per-version (4.0→n11.1.5.3,
7.1/8.1→n12.2.72.0); libfribidi/libharfbuzz версионно-гейчены (опции ffmpeg
только с 6.1 → для 4.x не включаются, libass тянет их внутри себя).
Panel-сторона (XC_VM) — как сейчас:
- FFmpeg лежит в Git LFS:
.gitattributes→src/bin/ffmpeg_bin/** filter=lfs; каталогиsrc/bin/ffmpeg_bin/{4.0,7.1,8.0}/. - Константы путей:
src/Core/Config/Binaries.php→FFMPEG_BIN_40 = BIN_PATH.'ffmpeg_bin/4.0/ffmpeg',_71 = 7.1/,_80 = 8.0/. - Выбор версии:
FfmpegPaths::resolve()маппит настройку8.0→_80,7.1→_71, иначе→_40(ffmpeg_cpu/ffmpeg_gpu, varchar(8), default4.0). 4.0неспроста:StreamProcess.php:943/947—-nofix_dts/-nofixтолько дляFFMPEG_BIN_40(legacy DTS-HD путьdts_legacy_ffmpeg).- Установка бинарей:
src/bin/install/update_binaries.shдетектит дистро (ubuntu_<major>.tar.gz/debian_<major>.tar.gz), пишетbin/bin_version.json. ffmpeg он сейчас НЕ качает — ffmpeg приезжает через LFS вместе с деплоем. - Паттерн-образец уже есть:
MaxMindCronJob+ProxyArchiveCronJob(cron:proxy) наGitHubReleases(GIT_OWNER, GIT_REPO_PROXY, update_channel); константы репо вsrc/Core/Config/AppConfig.php(GIT_OWNER,GIT_REPO_*).
Лейбл 8.x — РЕШЕНО: обновляемся до 8.1. Панель сейчас маппит настройку
8.0→FFMPEG_BIN_80, поэтому при проводке (Stage 4) панель приводится к 8.1.
0a. Что выяснили про сборки (провенанс + кодеки + DTS)
Три задеплоенных бинаря — три разных сборки (из ffmpeg -version):
4.0= master-снапшот XUI.one 2018 (XUI10FFMPEG, gcc 6.5/Ubuntu 14.04) — древний glibc, работает везде; несёт кастомный флаг-fix_dts.7.1= личная сборка mardock2009 (compiled-by-Mardock2009, Ubuntu 20.04) — без GPU (nvenc/cuvid пустые!). Кто на 7.1 — GPU-транскод не работает.8.0= наша сборкаXCVMна Ubuntu 22.04 → glibc 2.35 = первопричина.
Целевой набор кодеков выбран из того, что реально вызывает код
(StreamProcess/ProfileService), а не объединения трёх сборок:
- must: x264, x265, nvenc/cuvid/ffnvcodec (GPU:
*_cuvid,hevc_nvenc,-hwaccel cuvid), нативный aac +aac_adtstoasc, mp3lame, нативный DTS-декод (dca), libass/freetype/fontconfig, openssl, hls/segment/mpegts/flv-муксеры. - keep: vpx, opus, vorbis, theora, fdk-aac, librtmp (нативный rtmp уже есть, librtmp — паритет + rtmpe/rtmps), fribidi/harfbuzz (6.1+).
- drop: AV1 (aom/dav1d), libsrt (в коде
srt= субтитры SubRip, не протокол), xavs/xvid/webp/vidstab/openjpeg/xml2/amr/speex/bluray — ни одной ссылки. - GPU в статике безопасен: libnvidia-encode/libcuda грузятся
dlopenв рантайме → на CPU-ноде ffmpeg просто не видит карту, вреда нет.
-nofix_dts — кастомный CLI-флаг XUI, в стоке ffmpeg его НЕТ (7.1/8.0 не
понимают — проверено). В бинаре: -fix_dts "fix invalid dts", стоит рядом с
-copyts/-start_at_zero → тумблер коррекции «битых» DTS (по умолчанию ON; код
гасит его -nofix_dts для ac3/eac3 при dts_legacy_ffmpeg, StreamProcess:947).
Раз 4.0 пересобираем стоковым — панель обязана перестать слать -nofix_dts;
нативный dca-декод DTS сохраняется. Кандидат-замена — -copyts -fflags +igndts;
проверяется скриптами tools/dts-audio-test/ (gen-problem-stream.sh +
compare-audio.sh).
1. Стадии (обзор)
- Stage 0 — репозиторий
XC_VM_FFMPEG(сборщик, матрица, CI, docs). Запушен. - Stage 1 — первый релиз матрицы (собрать 18 ассетов, выпустить
1.0.0). - Stage 2 — фетч на панели:
update_binaries.sh/новый шаг тянетffmpeg_<label>_<distro>под дистро ноды, проверяетhashes.md5, кладёт вffmpeg_bin/<label>/. - Stage 3 — индекс + крон (
version.json+cron:ffmpegпо образцу maxmind). - Stage 4 — привести панель к лейблу
8.1(FfmpegPaths/Binaries/dropdown). - Stage 5 — вынос
ffmpeg_bin/*из Git LFS. - Stage 6 — Rocky_9 (dnf-порт
install_build_tools). - Stage 7 — валидация
4.0: реальная сборка4.4.5(линковка современных кодеков) + DTS-звук черезtools/dts-audio-test/(замена-nofix_dts).
2. Stage 1 — первый релиз XC_VM_FFMPEG
Цель: получить в релизах XC_VM_FFMPEG все ассеты, которые будет тянуть панель.
- На билд-машине с Docker:
make build(илиActions → Build & Release FFmpeg, тег bare-semver1.0.0, draft). - Проверить
verify_staticпрошёл для каждого билда (в логахlogs/), особенно для 4.0 (риск линковки, см. §8). - Сверить
hashes.md5содержит ровно 18 имён. - Опубликовать релиз (снять draft).
Решение (открыто): какой канал — stable/unstable (как у proxy,
GitHubReleases поддерживает оба; панель берёт update_channel).
3. Stage 2 — фетч ffmpeg на панели
По образцу ProxyArchiveCronJob/update_binaries.sh:
AppConfig.php: добавитьdefine('GIT_REPO_FFMPEG', 'XC_VM_FFMPEG');.- Детект дистро уже есть в
update_binaries.sh(DIST_ID/DIST_MAJOR→ubuntu_20/debian_12…). Переиспользовать его для имени ассета. - Для каждой нужной версии
<label>(см. §4, что реально ставить): скачатьffmpeg_<label>_<distro>.tar.gz, проверить md5 черезGitHubReleases::getAssetHash()(читаетhashes.md5), распаковать вBIN_PATH.'ffmpeg_bin/<label>/'(внутри архиваffmpeg,ffprobe,BUILD_INFO). - Использовать
CurlClient::downloadToFile()(стриминг, https-only, unlink-on-fail) — уже вынесен для proxy/maxmind. - Права:
ffmpeg/ffprobe→0755(как в текущем LFS-дереве). - Снять
-nofix_dtsизStreamProcess:947(кастомный флаг XUI, стоковый пересобранный4.0его не понимает). Заменить на проверенный эквивалент изtools/dts-audio-test/(кандидат-copyts -fflags +igndts) или убрать — DTS декодируется нативно (dca). Иначе legacy-DTS-команда упадёт.
Открытый вопрос: ставить все 3 версии на каждую ноду, или только выбранную
ffmpeg_cpu/ffmpeg_gpu + 4.0 (для DTS)? Меньше трафика vs. мгновенное
переключение в UI. Рекомендация: тянуть все, что реально выбираемы в dropdown.
4. Stage 4 — привести панель к лейблу 8.1
Решено обновляться до 8.1, поэтому панель приводится к нему (вариант B):
Binaries.php:FFMPEG_BIN_80→ffmpeg_bin/8.1/ffmpeg(или добавить_81).FfmpegPaths::resolve(): маппинг8.1.settings.php: значение в dropdown8.0→8.1.- Миграция настройки:
UPDATE settings SET ffmpeg_cpu='8.1' WHERE ffmpeg_cpu='8.0'(иffmpeg_gpu).
5. Stage 5 — вынос из LFS
После того как фетч (Stage 2–3) работает end-to-end и проверен на живой ноде:
git rm -r --cached src/bin/ffmpeg_binи убрать строку из.gitattributes.- Убедиться, что билд-архивы (
make main/make lb) больше не ждутffmpeg_bin/*в дереве (проверитьverify_no_lfs_pointersи упаковку). - Обновить установщик: свежая нода получает ffmpeg только через фетч.
- Освобождает LFS-квоту — главная причина всей затеи (как с proxy.tar.gz).
6. Stage 6 — Rocky_9
build_ffmpeg.sh целиком apt-ориентирован (install_build_tools,
--enable-набор универсален). Нужен dnf-порт:
apt-get→dnf, build-essential→gcc-toolset-13, имена -devel/tool-пакетов,
включить crb/EPEL для nasm/yasm. Добавить rocky_9→rockylinux:9 в матрицу
драйвера и versions.json. Панель уже умеет rocky в бандлах — имя ассета
ffmpeg_<label>_rocky_9.tar.gz встанет в общий механизм фетча.
7. Открытые вопросы / решения
- РЕШЕНО: лейбл 8.x →
8.1(§4);4.0пересобираем из4.4.5(§0a); набор кодеков зафиксирован (§0a). - Канал релиза (
stable/unstable). - Ставить все версии на ноду или только выбранную +
4.0(§3). - Частота
cron:ffmpeg(у maxmind/proxy свой интервал вcrontab). - Замена
-nofix_dts:-copytsvs убрать — по итогамtools/dts-audio-test/.
8. Риски
- FFmpeg 4.0 (
4.4.5) с современным набором кодеков (x265 4.1, vpx 1.15, fdk 2.0.3…): API новее, чем ждёт ffmpeg 4.x — линковка может упасть.libfribidi/libharfbuzzуже сняты для 4.x (нет до 6.1). При провале линковки прочего — пинить старую версию конкретного кодека для 4.0 (per-version хук). -nofix_dtsтеряется при пересборке4.0(кастом XUI) → без правки панели (Stage 2 п.6) legacy-DTS-команда упадёт. DTS-декод сохраняется нативно.- 7.1 сейчас без GPU (сборка mardock) → пересборка добавляет nvenc/cuvid; проверить, что GPU-профили заработали на 7.1-нодах после релиза.
- Полнота матрицы vs квота LFS: 18 архивов на релиз — но это release-assets, не LFS, и качается только нужный дистро (как maxmind/proxy).
- Обрыв фетча на ноде: должен быть TOFU-фолбэк на существующий бинарь (как у
ProxyArchiveCronJob: «using existing archive/local copy»), иначе нода без ffmpeg = нет VOD/транскода. - Тяжесть CI: каждый job — сборка ~20 кодеков из исходников. Параллельно 6,
timeout-minutes: 240. Первый релиз лучше собрать локально (make build).