Fall back to separate video and audio downloads

Playing with video only worked for clips YouTube still serves as a single
progressive file, and it mostly does not: the log showed "Requested
format is not available" and every track fell back to sound only.

A progressive format is still preferred when offered — one download, one
decode — but when there is none, video and audio are fetched in parallel
and handed to one ffmpeg over separate pipes, which pairs them by
timestamp. This also lifts the 360p ceiling: the height is now a CPU
choice rather than a limit.

The extra-descriptor plumbing (two inputs, two outputs on one ffmpeg) was
verified against synthetic media: exactly 5.0s of PCM and 120 whole
frames at 24 fps, no partial tail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-09-09 02:21:14 +03:00
co-authored by Claude Opus 5
parent a9b680c418
commit 9285fd7fbd
5 changed files with 370 additions and 313 deletions
+9 -5
View File
@@ -249,15 +249,19 @@ VIDEO_FPS=24
Как это устроено и почему так:
- **Только YouTube и только 360p.** Стримить можно лишь прогрессивный формат — один файл со
звуком и картинкой. Раздельные дорожки (720p и выше) yt-dlp обязан сначала скачать целиком
и лишь потом склеить, то есть воспроизведение началось бы после полной загрузки. Отдавать
ffmpeg прямые ссылки на CDN тоже нельзя: YouTube их для сторонних клиентов подвешивает.
- **Только YouTube.** Для остальных источников картинки нет, трек играет звуком.
- **Два способа получить картинку.** Если YouTube отдаёт прогрессивный формат (один файл со
звуком и видео) — используется он: одна загрузка, один декодер. Такие форматы встречаются всё
реже, поэтому есть запасной путь: видео и звук качаются двумя процессами параллельно и
сводятся одним ffmpeg по таймкодам. Склейка средствами yt-dlp не годится — он скачивает оба
потока целиком, прежде чем выдать первый байт; прямые ссылки на CDN тоже: YouTube подвешивает
их для сторонних клиентов.
- **Один процесс ffmpeg, два выхода:** PCM для голосовой дорожки и сырые I420-кадры для видео.
Темп задаёт `-re`, иначе кадры улетали бы вперёд звука и съедали память — распакованный кадр
720p весит 1.4 МБ.
- **Цена.** Кодирование видео ложится на CPU сервера и держится всё время трека, в отличие от
почти бесплатного звука. Ставьте `VIDEO_FPS` пониже, если нагрузка мешает.
почти бесплатного звука. 360p по умолчанию выбран из осторожности; поднимайте до 720p, если
машина тянет, и снижайте `VIDEO_FPS`, если нагрузка мешает.
- Живые трансляции и не-YouTube источники играют звуком, как раньше.
## Прокси, когда YouTube недоступен