Add documentation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 13:23:58 +03:00
parent 84fb48f39d
commit b077388b74
24 changed files with 7157 additions and 8 deletions

61
docs/research/README.md Normal file
View File

@@ -0,0 +1,61 @@
# Исследование движков воспроизведения (начало проекта, 2026-10-11…12)
Это исследование сделано **до** написания кода: по исходникам, issue-трекерам, Maven и дампу тестового ТВ. Часть выводов потом подтвердилась на реальном телевизоре, часть оказалась неверной. Что изменилось после тестов, сказано в конце этого файла, а итог описан в [`../playback.md`](../playback.md).
## Файлы
| Файл | О чём |
|---|---|
| [`decisions.md`](decisions.md) | Принятые решения: гибридный движок, выбор движка, fallback, тестовый ТВ, что проверить прототипом (часть 7 общего [`jellyfin-client-research.md`](jellyfin-client-research.md)) |
| [`media3.md`](media3.md) | media3/ExoPlayer: Dolby Vision, HDR, tunneling, частота дисплея, passthrough, FFmpeg, ASS (libass), контейнеры, DeviceProfile из jellyfin-androidtv |
| [`engines.md`](engines.md) | Как устроены несколько движков в других клиентах (Findroid, Wholphin, JellyPlay, Swiftfin, Plezy, Kodi…), дизайн абстракции, Gradle-модули, libVLC против libmpv, алгоритм выбора, runtime-fallback |
| [`device-xiaomi.md`](device-xiaomi.md) | Тестовый ТВ Xiaomi S Pro Mini LED 75 и семейство MediaTek: известные баги декодеров, DV, passthrough, чек-лист проверок |
| [`library-profile.md`](library-profile.md) | Профиль медиатеки тестового сервера: какие контейнеры, кодеки, HDR, аудио и субтитры встречаются и сколько |
| [`tv-dump/`](tv-dump/) | Сырые дампы ТВ: `media_codecs-mt5896.xml`, `dumpsys display`, `audio_policy` |
Полный исходный документ со всеми частями (Jellyfin API, обзор клиентов, libVLC, Android TV, инструменты): [`jellyfin-client-research.md`](jellyfin-client-research.md).
## Главное из исследования
**Цель** — воспроизводить всё, что можно, без серверного транскода и с правильным HDR и Dolby Vision. Официальный клиент Jellyfin, Moonfin и Dune на этом ТВ спотыкались каждый на своих файлах: транскодировали, давали тусклый HDR или зависали.
1. **Одного движка недостаточно.**
- media3/ExoPlayer — единственный путь к аппаратному декодированию с HDR10, HDR10+, HLG и DV, а также к passthrough. Но он не открывает M2TS, ASF/WMV, ISO/BDMV, MKV со сжатием zlib, не умеет программно H.264 Hi10P, VC-1, MPEG-4 ASP и не рисует ASS сам.
- libVLC и libmpv играют почти всё через ffmpeg, но HDR у них ненадёжен.
- Отсюда **гибрид: media3 основной, libVLC запасной.**
2. **Запасным выбран libVLC 3.7.x, а не libmpv.**
- Это официальный артефакт VideoLAN со стабильным Java API, внутри libass, PGS и VobSub, есть passthrough.
- Стоковый mpv-android переводит HDR в SDR через GLES, а AAR у него неофициальный.
- Цена libVLC — +24–55 МБ на ABI.
3. **Автоматический выбор движка до запроса PlaybackInfo.** Данные файла от Jellyfin (контейнер, кодек, битность, `VideoRangeType`, профиль DV, дорожки) сравниваются с возможностями устройства (`MediaCodecList`, HDR-типы дисплея, `AudioTrack.isDirectPlaybackSupported`). У каждого движка свой DeviceProfile.
4. **Runtime-fallback по образцу Plezy.** Если движок упал, завис или не дал кадра, сессия переходит на другой движок с той же позиции; если не справился и он — серверный транскод. Среди Jellyfin-клиентов такого нет ни у кого.
5. **Архитектура:**
- свой узкий интерфейс `PlaybackEngine` плюс интерфейсы-возможности (задержка звука, стиль субтитров и т. п.);
- каждый движок — отдельный Gradle-модуль, подключается через Hilt `@IntoSet` (позже DI перевели на Koin);
- реализация движка «как media3 `Player`» (Findroid, Wholphin) приводит к десяткам `TODO()`, поэтому так не делаем.
6. **Риски, найденные заранее:**
- DV P7 в media3 без DV-декодера не откатывается на HEVC;
- DV + HDR10+ зависает на MediaTek (#1895);
- HEVC-декодер MTK падает посреди потока (#3421), и `setEnableDecoderFallback` это не ловит;
- вечная буферизация при AC3 passthrough после быстрых перемоток (#3407);
- TrueHD и DTS-HD из приложения на встроенных динамиках, скорее всего, не выйдут в passthrough;
- смену частоты и HDR-режима media3 сам не делает.
7. **Тестовый ТВ** (дамп через adb):
- MediaTek MT9689, Android 14, **только 32-bit userspace (armeabi-v7a)**, 2,4 ГБ RAM;
- один режим дисплея 4K@60;
- дисплей заявляет DV, HDR10, HDR10+ и HLG;
- аппаратные AVC/HEVC/VP9/AV1 до 8K, MPEG-2/VC-1/MPEG-4 до 1080p.
## Что тесты потом опровергли или уточнили
| Ожидание из исследования | Как оказалось на ТВ |
|---|---|
| DV P7 есть в железе (по XML-дампу) | В рантайме `MediaCodecList` **не показывает** `dvhe.dtb` (P7). Наличие в XML не гарантирует наличие в API |
| H.264 Hi10P — только программно (libVLC) | `c2.mtk.avc.decoder` заявляет High10 и **играет Hi10P аппаратно** |
| DV + HDR10+ виснет на MediaTek (#1895) | На этом ТВ играет без зависаний, и с DV-декодером, и как базовый слой |
| DV-декодер даёт «тусклую» картинку | ТВ действительно включает режим Dolby Vision (значок, DispService `Hdr Dolby`). «Тускло» — это режим изображения DV в настройках ТВ, а не поломка. DV-декодер включён по умолчанию |
| Смена частоты нужна вручную (`preferredDisplayModeId`) | Android видит один режим 4K@60, но **на аппаратном видеослое ТВ сам переключает панель**: 23,976 → 119,88 Гц, 25 → 100 Гц. Через GPU-путь (TextureView) этого нет |
| HTTPS для libVLC достаточно проверить на самоподписанном сертификате | libVLC (GnuTLS) через reverse proxy ненадёжен даже с нормальным сертификатом: зацикливается prefetch, перемотка к концу файла ждёт по ~10 с. Решено локальным HTTP-прокси внутри приложения |
| `VLCVideoLayout` и libVLC — вопрос API | Главные проблемы VLC оказались в звуке (многоканальный PCM на этом ТВ беззвучен) и в сетевом кэше (prefetch выбрасывает прочитанное) |
| VC-1 через media3, если есть декодер | Декодер зарегистрирован как MIME `video/VC1` (регистр!), а media3 ищет `video/wvc1` |
| Аппаратное декодирование в libVLC — по умолчанию | Опрос MediaCodec модулем VLC на MediaTek длится ~45 с. Аппаратно в VLC включаем только для видео больше 1080p |