Содержание статьи +
- TL;DR
- Зачем это нужно
- Плеер – это конечный автомат, а не кнопка
- Подсистема 1 – Загрузчик манифеста
- Подсистема 2 – Загрузчик сегментов
- Подсистема 3 – Контроллер ABR
- Подсистема 4 – Менеджер буфера и source buffer
- Подсистема 5 – Конвейер декодирования
- Подсистема 6 – Мост DRM
- Подсистема 7 – Телеметрия и восстановление после ошибок
- Нативный плеер против JavaScript-плеера: когда какой выигрывает
- iOS Safari, Managed Media Source и история про энергопотребление
- Smart TV: почему «тот же hls.js» там не поедет
- Что изменилось в 2026 году
- Где здесь Фора Софт
- Типичные ловушки, в одном абзаце
- Выводы
- Что почитать дальше
TL;DR
Плеер видеостриминга – это не «тег <video> плюс кнопка Play». Это маленькая распределённая система внутри браузера: семь подсистем одновременно общаются с CDN, декодером, буфером, модулем DRM и эндпоинтом телеметрии. Семь подсистем такие: маленький текстовый файл-манифест, который плеер скачивает первым; загрузчик, который тянет медиа короткими чанками; контроллер адаптивного битрейта, выбирающий следующий уровень качества; менеджер буфера, передающий эти чанки браузеру; конвейер декодирования, работающий внутри браузерного медиа-движка; мост DRM, разблокирующий зашифрованные сегменты; и слой телеметрии, отправляющий события ребуферизации в вашу аналитику. Два веб-стандарта – Media Source Extensions (MSE) и Encrypted Media Extensions (EME) – связывают JavaScript-часть с нативной браузерной, а тонкий слой новых API (Managed Media Source в iOS Safari, MSE-in-Workers в Chrome, WebCodecs для низкоуровневого доступа) меняет вид каждой подсистемы в 2026 году. Сначала прочитайте эту статью, а потом разборы конкретных плееров – hls.js, Shaka Player, dash.js, Video.js v10 – с одинаковым словарём в голове.
Зачем это нужно
Когда зритель говорит «видео не работает», он почти всегда имеет в виду, что отказала одна из семи подсистем: манифест не распарсился, загрузчик сегментов словил таймаут, ABR-логика выбрала не ту рендицию, буфер опустел, декодер отверг кодек, рукопожатие DRM упало, или телеметрия молча проглотила событие и об этом никто не узнал. Если вы поставляете видео хоть в каком-то масштабе, вы будете читать этот стек-трейс, заводить под него Jira-тикет и объяснять его клиенту – поэтому семь имён должны быть у вас в голове. Статья написана для продакт-менеджеров, основателей и маркетинг-лидов, которым нужно говорить с инженерами о проблемах плеера, не теряясь, и для инженеров, входящих в команду плеера, которым нужна карта до того, как они начнут разбирать территорию. Никаких предварительных знаний о стриминговых протоколах не требуется. К концу вы научитесь смотреть на исходники любого open-source плеера и понимать, какой файл отвечает за какую подсистему.
Плеер – это конечный автомат, а не кнопка
Многие читатели приходят с моделью: плеер – это кнопка Play. Нажми – пошло видео, нажми ещё раз – встало. Эта модель неверна полезным образом: она описывает контракт перед пользователем, но прячет семь подсистем, которые этот контракт реализуют.
Лучше думать так: плеер стриминга – это конечный автомат, который тянет медиа из интернета по нескольку секунд за раз, отдаёт эти секунды встроенному в браузер видео-движку и слушает события вида «дай ещё» и «я сломался». У самого браузерного видео-движка есть пять состояний готовности, описанных в стандарте WHATWG HTML: HAVE_NOTHING, HAVE_METADATA, HAVE_CURRENT_DATA, HAVE_FUTURE_DATA, HAVE_ENOUGH_DATA. Работа плеера – двигать движок от одного состояния к следующему и никогда не давать ему откатываться назад. Когда движок откатывается с HAVE_FUTURE_DATA обратно в HAVE_CURRENT_DATA, ровно в этот момент зритель видит спиннер, а в дашборде аналитики появляется событие ребуферизации.
Остальная часть статьи – экскурсия по семи подсистемам, которые двигают автомат вперёд. Они универсальны: каждый браузерный плеер устроен из этих семи блоков, независимо от того, поставляет он HLS, MPEG-DASH, CMAF или Media over QUIC. Имена JavaScript-файлов в hls.js, Shaka Player, dash.js и Video.js v10 разные – а семь работ идентичны.
Подсистема 1 – Загрузчик манифеста
Прежде чем плеер сможет скачать хоть один байт видео, он должен получить маленький текстовый файл – манифест, телефонную книгу всех качеств и всех сегментов контента. Два формата манифеста доминируют в открытом вебе: плейлист .m3u8 от HTTP Live Streaming (HLS) и Media Presentation Description .mpd от MPEG-DASH. Оба описаны в нормативных документах (IETF RFC 8216 для HLS, ISO/IEC 23009-1 для DASH).
Типичный multi-variant HLS-плейлист – это десяток строк обычного текста. Он перечисляет доступные рендиции – так плеер называет одно качество, например «1080p, 5 Мбит/с, H.264» – и указывает на media playlist каждой рендиции, в котором уже лежат URL сегментов. Типичный DASH MPD – пара килобайт XML, делающих то же самое более структурированно: верхний Period, по одному AdaptationSet на тип медиа (видео, аудио, субтитры) и по одному Representation на каждую рендицию внутри.
Работа загрузчика манифеста звучит тривиально – скачать текстовый файл, распарсить, отдать структуру дальше. На практике это слой самых частых продакшен-падений по одной причине: манифест – единственный объект во всём конвейере, чья потеря фатальна. Если плеер не достучался до манифеста, фоллбэка нет – воспроизведение просто не начнётся. Поэтому в загрузчике больше всего ретраев, агрессивных cache-buster-заголовков и кода «попробовали пять CDN параллельно» в продакшен-стеках. Каждый плеер выставляет таймаут на загрузку манифеста (обычно 10–20 секунд) и настраиваемую политику ретраев с экспоненциальным бэк-оффом.
Для live-стримов загрузчик работает не один раз – он работает вечно. Каждые несколько секунд плеер перезагружает манифест, чтобы узнать о новых сегментах на live-кромке. Low-Latency HLS добавляет в плейлист подсказку «blocking reload», которая просит сервер держать соединение открытым, пока не появится следующая часть, – но базовый цикл перезагрузок одинаков во всех live-форматах.
Подсистема 2 – Загрузчик сегментов
После того как манифест распарсен, плеер знает URL каждого медиа-сегмента шоу. Загрузчик сегментов – слой, который их фактически скачивает. Сегмент – короткий кусок видео, обычно 2–6 секунд для live и 10 секунд для VOD, упакованный в ISO Base Media File Format (fragmented MP4) или MPEG-2 Transport Stream. Загрузчик делает один HTTPS-запрос на сегмент.
Два проектных решения определяют хороший загрузчик: параллелизм и приоритеты запросов. Наивный загрузчик качает сегменты строго последовательно; продакшен-загрузчик держит 2–3 сегмента в полёте одновременно, чтобы кривая throughput-vs-latency выглядела разумно. Логика приоритетов решает, что качать первым на старте – самый низкобитрейтный первый сегмент, чтобы воспроизведение началось как можно быстрее, потом более высокобитрейтный второй сегмент, чтобы воспользоваться сетью, которую первый запрос только что измерил.
Загрузчик – это ещё и место, где добавляется Common Media Client Data (CMCD): маленький набор ключ-значение, который плеер прицепляет к каждому запросу сегмента и который сообщает CDN, что плеер сейчас делает: какая это сессия, какая длина буфера, какой битрейт он целит, является ли запрос первым после старта. CMCD описан в CTA-5004 и существенно расширен в CTA-5004-A (CMCDv2, февраль 2026). Это одно из самых дешёвых улучшений надёжности стриминг-продукта: локально плеер ничего не выигрывает, но каждая строка лога CDN теперь несёт контекст, нужный инженеру incident-response, чтобы дебажить ребуферизацию в продакшене.
Подсистема 3 – Контроллер ABR
Adaptive bitrate (ABR) – алгоритм, который перед каждой загрузкой сегмента решает, какую рендицию запросить следующей. Формулировка задачи маленькая, а реализация – самая вариативная часть любого плеера. Маленькое изменение в ABR-логике сдвигает rebuffer ratio и средний битрейт на измеримые величины в A/B-тесте на миллион сессий, поэтому любая серьёзная стриминг-команда либо тюнила стоковый ABR, либо написала свой.
В продакшене живут четыре семейства ABR. Throughput-based алгоритмы оценивают недавнюю пропускную способность сети и выбирают самую высокую рендицию, чья битрейт-цифра укладывается под неё, – самый простой дизайн и до сих пор дефолт во многих плеерах. Buffer-based алгоритмы игнорируют throughput и смотрят только на то, сколько видео сидит в буфере; алгоритм BOLA, опубликованный Spiteri и соавторами в 2016 году, – открытая референсная реализация. Hybrid алгоритмы смешивают оба подхода; семейство Model Predictive Control (MPC) и режим «DYNAMIC» в dash.js – типичные примеры. Neural / learning-based алгоритмы – Pensieve, Comyco, Kairos – обучают маленькую RL-политику на корпусе session traces и используют её как ABR; они уже в продакшене у нескольких крупных операторов.
У каждого ABR-алгоритма одинаковый вход – поток недавних длительностей загрузок и текущий уровень буфера. У каждого алгоритма одинаковый выход – целочисленный индекс в списке рендиций. Контроллеру не нужно «знать» о кодеках, контейнерах или транспорте – это чистая функция состояния сети и буфера в решение о качестве. Поэтому ABR можно подменить одним файлом в любом крупном open-source плеере.
В контроллере же живёт и большая часть продакшен-тюнинга. Типичный продукт поставляется с двумя-тремя оверрайдами: ограничить максимальную рендицию на сотовых сетях, держать рендицию стабильной на первых трёх сегментах, чтобы избежать мигания низкого качества на старте, переключаться в buffer-based режим, когда воспроизведение устаканилось. Ничего из этого нет в опубликованных статьях про алгоритмы – это устный фольклор команд, гоняющих плеер против настоящей аудитории.
Подсистема 4 – Менеджер буфера и source buffer
Когда сегмент скачан, у плеера возникает проблема: тег <video> в браузере не умеет «принять кусок MP4». Тег умеет проигрывать законченный файл через атрибут src, а плеер стриминга собирает файл инкрементально, в памяти, по ходу показа. Эту проблему решает Media Source Extensions (MSE) – спецификация W3C (на момент написания – Working Draft 4 ноября 2025 года, последняя формальная Recommendation от 17 ноября 2016), дающая JavaScript API для добавления байтов в медиа-конвейер браузера.
В MSE два объекта. MediaSource – JavaScript-прокси для медиапотока браузера: вы создаёте его, привязываете к тегу <video> через video.src = URL.createObjectURL(mediaSource), и тег видит его как настоящий источник видео. SourceBuffer – JavaScript-хэндл на буфер готовых-к-декодированию медиа внутри браузера: вы вызываете sourceBuffer.appendBuffer(arrayBuffer) с байтами скачанного сегмента, и браузер парсит, декодирует и добавляет их на проигрываемую таймлайн.
Менеджер буфера – код плеера, решающий, какие сегменты добавлять, в каком порядке и когда удалять старые. Live-плеер обычно держит в SourceBuffer тридцать секунд видео; VOD-плеер – одну-две минуты. Когда пользователь сикает за пределы текущего окна, менеджер чистит буфер и начинает заново от точки сика.
В менеджере буфера живёт и обработка пропусков (gap-handling). У сегментов изредка бывают пропуски в один кадр из-за бага в пакетировщике или из-за границы у энкодера, и наивный плеер будет сидеть в пропуске вечно, ожидая видео, которое не придёт. У любого продакшен-менеджера буфера есть правило «если currentTime не двигается N секунд, а следующий sample находится в пределах K миллисекунд – прыгнуть вперёд»; конкретные константы – маленькая, но очень оттюненная часть кода каждого плеера.
Одно обновление 2026 года стоит назвать отдельно. Chrome 108 и выше позволяют использовать MSE внутри dedicated Worker: парсинг сегментов и буферная арифметика убираются с главного UI-потока, и воспроизведение 4K больше не конкурирует с JavaScript страницы за CPU. Спецификация W3C MSE добавила объект MediaSourceHandle, который пересекает Worker-границу и привязывается к <video> через video.srcObject на главном потоке. Плееры, освоившие Worker-MSE, видят измеримое падение событий ребуферизации на ноутбуках попроще.
Второе обновление 2026 – Managed Media Source (MMS) от Apple, поставленный в Safari 17.0 на iPad и Mac и в Safari 17.1 на iPhone. MMS сохраняет API-поверхность MSE, но возвращает решения о пропускной способности и памяти браузеру: браузер может попросить плеер прекратить загрузку или удалить старые сегменты, когда деградируют батарея, память или сеть. Путь апгрейда ненавязчивый: плеер делает feature-detect на MMS, на других браузерах фоллбэчит на классический MSE, и одна кодовая база работает энергоэффективно на любом устройстве Apple.
Подсистема 5 – Конвейер декодирования
Менеджер буфера не декодирует видео сам – он отдаёт байты браузеру, а браузерный медиа-движок берёт дело в свои руки. Конвейер декодирования – цепочка компонентов внутри браузера, превращающая MP4-сегмент в пиксели на экране: демультиплексор, разделяющий аудио и видео; видео-декодер, превращающий сжатые кадры в сырые; аудио-декодер, превращающий сжатые сэмплы в сырые; рендерер, отдающий кадры в GPU; и тактовый генератор, держащий аудио и видео в синхроне.
Для разработчика стриминг-плеера конвейер декодирования в основном невидим – байты входят через MSE, пиксели выходят на теге <video>, всё между ними обрабатывает браузер. Что заботит разработчика плеера – это поддержка кодеков, которая варьируется по браузерам и операционным системам и меняется чаще, чем большинству команд кажется. Логика старта плеера спрашивает у браузера, какие кодеки он умеет декодировать (MediaSource.isTypeSupported('video/mp4; codecs="avc1.640028,mp4a.40.2"')), выбирает рендиции, чьи codec strings подходят, и молча отфильтровывает остальные.
В конвейере декодирования имеет значение и аппаратное ускорение. На современном устройстве с аппаратным декодером H.264, HEVC или AV1 браузер маршрутизирует байты на кремний, который декодирует 4K@60fps, используя меньше 5% CPU. Без аппаратной поддержки – типично для AV1 на старых ноутбуках в 2026 – браузер фоллбэчит на программный декодер, и CPU встаёт на 100%. Это одна из самых частых продакшен-проблем, которая выглядит как «баг плеера», но на самом деле – пробел в аппаратных кодеках; единственное лечение – отфильтровать AV1-рендиции из манифеста для устройств без нужного кремния.
Маленький, но растущий класс плееров обходит MSE полностью и использует API WebCodecs, декодируя кадры в JavaScript на уровне отдельного кадра и рендеря их в <canvas>. WebCodecs (опубликован как W3C Candidate Recommendation Snapshot) необходим в двух кейсах: live-стриминг с задержкой меньше секунды, где буферизация, навязанная MSE, слишком дорога, и любые приложения, где нужен покадровый доступ к декодированным пикселям (in-browser редактирование, ИИ-эффекты, screen-share с энкодером прямо в WebTransport-аплоад). Для массового HLS- или DASH-воспроизведения MSE остаётся правильным инструментом – WebCodecs отдаёт слишком много за слишком малое.
Подсистема 6 – Мост DRM
Если контент защищён, у плеера есть шестая работа: убедить браузерный Content Decryption Module (CDM), что этой сессии разрешено расшифровывать сегменты. Механизм – API W3C Encrypted Media Extensions (EME).
EME – это не DRM. Это стандартизированный канал сообщений между JavaScript плеера и нативным CDM браузера, плюс маленький конечный автомат для запросов лицензий. CDM браузера – Widevine в Chrome, Firefox и Edge, FairPlay в Safari, PlayReady в legacy Edge и Windows – это закрытый бинарник, который делает фактическое расшифрование внутри песочницы; работа плеера – носить сообщения между CDM и сервером лицензий, который держите вы.
Пять шагов EME-сессии звучат просто и удивительно стабильны в реализации: navigator.requestMediaKeySystemAccess(keySystem, configurations) спрашивает у браузера, есть ли у него CDM, умеющий обращаться с нужным плееру кодеком, контейнером и DRM; createMediaKeys() инстанцирует CDM-сессию; setMediaKeys() привязывает её к тегу <video>; generateRequest() производит payload запроса лицензии, который плеер POST-ит на сервер лицензий; ответ скармливается обратно в CDM, и расшифрование начинается. Каждая строка этого потока есть в W3C EME Recommendation.
Сложность в продакшене – не EME API, а матрица трёх DRM-систем на каждое устройство мира. У одного только Widevine три уровня безопасности (L1, L2, L3), определяющие, проиграет ли браузер 4K, 1080p или только 480p защищённого стрима, и уровень – это свойство устройства, которым владеет пользователь. FairPlay обязателен в iOS Safari для любого защищённого контента. PlayReady обязателен в Xbox и в длинном хвосте smart-TV платформ. Современный OTT-плеер обязан поддерживать все три, обязан запрашивать их в правильном порядке и обязан показывать понятную ошибку, если ни один не доступен.
DRM – тема на целый блок статей (Блок 9, 9.1–9.5). В этой статье важна позиция: мост DRM сидит между менеджером буфера и конвейером декодирования, перехватывая каждый добавленный буфер прямо перед декодером, чтобы нешифрованные байты никогда не покидали песочницу CDM.
Подсистема 7 – Телеметрия и восстановление после ошибок
У седьмой подсистемы самый прямой эффект на выручку клиента, и именно её большинство команд недостраивает первой. Телеметрия – слой, который слушает каждое событие, выпущенное предыдущими шестью подсистемами (сегмент скачан, сегмент упал, уровень буфера изменился, ABR переключил рендицию, запрос лицензии вернулся, декодер выбросил ошибку, воспроизведение встало), и пересылает их в реальном времени в аналитическую платформу.
Четыре главные метрики: video startup time (сколько прошло от клика пользователя до первого кадра), rebuffer ratio (доля времени просмотра, проведённая в спиннере), playback failure rate (доля сессий, в которых первый кадр так и не появился) и exit-before-video-start (доля пользователей, ушедших ещё до того, как они нажали Play). Mux Data, Conviva, Bitmovin Analytics, Datazoom и NPAW выставляют эти четыре как заголовочные плитки своих дашбордов, потому что любое исследование оттока зрителей за последние пятнадцать лет показывает их как четыре самых предиктивных переменных для удержания.
Разумная цель по rebuffer ratio – меньше 1%; ниже 0.5% – то, чего добивается оттюненный продукт; всё, что выше 3%, сломано в смысле, при котором команда должна обращаться с этим как с продакшен-инцидентом. Арифметика небольшая, но в первый раз стоит показать вслух. Если пользователь смотрит 45-минутный эпизод и ребуферится в сумме 60 секунд, отношение равно 60 / (45 × 60), то есть 60 / 2700, то есть 0.022, то есть примерно 2.2%. 2.2% – это вдвое больше верхнего приемлемого порога; команда ожидаемо увидит на этих сессиях рост exit rate.
Половина подсистемы, отвечающая за восстановление, – маленький набор автоматических ретраев, которые плеер запускает до того, как сдаться и показать красный экран ошибки. Типовые такие: ретраить манифест с экспоненциальным бэк-оффом, если первая загрузка упала; ретраить упавший сегмент до N раз; пересоздать MediaSource и пере-привязать к <video>, если состояние буфера стало неконсистентным; перепрыгнуть через одно-кадровый пропуск, если currentTime стоит две секунды; фоллбэкнуть на следующий доступный CDN-URL, если текущий возвращает 5xx. Ничего из этого нет ни в одной спецификации – это накопленная продакшен-мудрость каждой плеерной команды, которая когда-либо стояла на дежурстве во время Super Bowl.
Нативный плеер против JavaScript-плеера: когда какой выигрывает
Семь подсистем описывают, как работает JavaScript-плеер в браузере. Есть и вторая, более простая форма, тоже идущая в продакшен: нативный плеер, который отдаёт URL манифеста встроенному в ОС видеоконвейеру и даёт системе сделать всё.
Хрестоматийный пример – iOS Safari: присвоить URL HLS-манифеста атрибуту src тега <video> – значит запустить под капотом AVPlayer, и реализация Apple сама обрабатывает загрузчик манифеста, загрузчик сегментов, ABR, менеджер буфера, конвейер декодирования, DRM-мост (через FairPlay) и даже большую часть телеметрии. JavaScript-плеер сжимается до «выставить src, повесить пару слушателей событий, нарисовать кастомный UI поверх». Нативный плеер выигрывает по батарее, по first-frame latency (конвейер декодирования Apple быстрее любого JS-плеера) и по поддержке AirPlay, которую MSE-плеер легко не повторит.
Нативный плеер также проигрывает в трёх конкретных вещах. Он говорит только на протоколах, которые понимает ОС: HLS в iOS Safari, HLS и DASH в Android, ни тот ни другой на smart-TV платформе, которая ещё не выпустила этот кодек. Он раскрывает очень мало своего внутреннего состояния: интеграция Mux Data в нативный iOS-плеер имеет меньше измерений, чем та же интеграция в сессию Shaka Player. И он поставляется в темпе релизов Apple, а не вашем: фикс бага в нативном HLS-движке выходит через 6–12 месяцев.
Выбор в 2026 году редко звучит как «JavaScript-плеер везде» или «нативный плеер везде». Большинство продакшен-стеков поставляют оба: hls.js или Shaka в Safari только если MSE доступен и команда хочет более тугого контроля, нативный HLS в Safari иначе; Shaka Player в Chrome на Android; ExoPlayer на Android TV; AVPlayer на tvOS; пер-платформенный нативный плеер на каждой ОС smart-TV. Решение по платформе – функция от поддержки MSE, покрытия кодеками, требований телеметрии и готовности команды поддерживать порт плеера.
iOS Safari, Managed Media Source и история про энергопотребление
Долгое время iOS Safari вообще не поддерживал MSE – поэтому в каждом видео-стеке 2010-х в итоге появлялся «iOS-путь», отдающий URL манифеста HLS нативному плееру, и «всё остальное», на котором крутился hls.js или Shaka. Safari 17.0 на iPad и Mac в сентябре 2023 и Safari 17.1 на iPhone в октябре 2023 это изменили – но с ограничением: iOS Safari поставляет Managed Media Source, не классический MSE.
Разница важна по одной причине. Классический MSE даёт JavaScript плеера полный контроль над загрузкой, аппендом и эвикцией медиа; плеер может держать на устройстве пользователя две минуты буфера независимо от того, у пользователя 1% батареи или 100%. Managed Media Source инвертирует контроль: браузер ведёт бюджет memoryUsage и эмитит события (startstreaming, endstreaming), сообщающие плееру, когда загружать и когда остановиться. Работу по-прежнему делает плеер – браузер только сигналит намерение – но сигналы достаточно агрессивны, чтобы MMS-плеер на iPhone расходовал измеримо меньше батареи, чем расходовал бы MSE-плеер.
Apple добавили ещё одну способность, которой MSE не мог иметь никогда: AirPlay поверх MMS. Фича WebKit 2024 года позволяет MMS-плееру передать защищённый стрим на Apple TV через AirPlay с переоформлением лицензии FairPlay средствами системы. Классический MSE этого не мог никогда: в момент привязки MediaSource к тегу <video> AirPlay отключался. Для любого продукта, который хочет каст с iPhone на Apple TV защищённого контента, MMS – единственный путь.
Практический совет 2026 года: сначала делайте feature-detect ManagedMediaSource, потом фоллбэк на MediaSource – и пусть один кодпас работает везде. hls.js, Shaka и Video.js v10 поставляют такую логику feature-detect из коробки.
Smart TV: почему «тот же hls.js» там не поедет
Архитектура из семи подсистем универсальна по идее. Реализации – нет. Smart TV – Samsung Tizen, LG webOS, Roku, Android TV, Amazon Fire TV, Apple tvOS, Hisense Vidaa плюс длинный хвост региональных платформ – каждая поставляет свой рантайм, поддерживающий своё подмножество веб-платформы.
Часть из них поставляет настоящий браузер. Samsung Tizen и LG webOS гоняют форк WebKit с поддержкой MSE и EME, так что JavaScript-плеер вроде hls.js или Shaka там запускается с платформенными тюнингами (меньший буфер, консервативный выбор кодеков, ограниченное использование новых API). Другие платформы – канонический пример Roku – поставляют доменный скриптовый язык (BrightScript) и JavaScript не гоняют вообще; плеер на Roku – это компонент Roku SDK, а не JavaScript-библиотека. Android TV использует ExoPlayer – нативную библиотеку на Kotlin/Java, никаких браузерных плееров. tvOS – AVPlayer с нативной Swift-обвязкой.
Импликация для стриминг-продукта: «команда плеера» – редко одна команда. Типичный OTT- или e-learning-стек имеет минимум три: веб-плеер на JavaScript для Chrome, Firefox, Edge и Safari; мобильный плеер на ExoPlayer для Android и AVPlayer для iOS; и TV-плеер с per-platform интеграцией на Tizen, webOS, Roku, tvOS, Android TV, Fire TV и Vidaa. У каждой команды свой матрица кодеков, своя матрица DRM, своя интеграция телеметрии и свой бэклог багов. Семь подсистем – одни и те же; исходные деревья – очень разные.
Что изменилось в 2026 году
Четыре обновления 2026 стоит назвать отдельно, потому что они меняют то, что плеер может поставлять.
MSE-in-Workers больше не «экспериментальная» опция. Chrome 108 сделал её стабильной, последний Working Draft MSE (4 ноября 2025) делает паттерн cross-Worker MediaSourceHandle нормативным, и hls.js, Shaka и dash.js все поддерживают его конфиг-флагом. Перенос парсинга сегментов в Worker измеримо снижает нагрузку на главный поток и улучшает rebuffer ratio на менее мощных устройствах.
Common Media Client Data version 2 (CTA-5004-A, февраль 2026) расширяет оригинальный CMCD более крупным набором ключей и более чёткой схемой для отчётности по live-кромке. Плееры, освоившие CMCDv2, поставляют более богатый контекст в свои CDN и в свои аналитические платформы.
WebCodecs теперь широко применим в Chrome, Edge и Firefox; Safari поддерживает VideoDecoder, хотя не полную сторону энкодера. Продакшен-плееры на WebCodecs всё ещё редкость для массового HLS или DASH, но для low-latency live (sub-500 ms), in-browser редактирования и любого продукта, которому нужен покадровый доступ, WebCodecs – слой, который стоит выучить.
Media over QUIC (MoQ) – протокол, о котором плеерная команда ещё не должна была думать, но придётся через 12–18 месяцев. draft-ietf-moq-transport от IETF MoQ Working Group итерируется примерно каждые два месяца; референс-плееры существуют в Cloudflare moq-rs и в Meta. MoQ-осведомлённая архитектура – это те же семь подсистем с двумя изменениями: загрузчик манифеста исчезает (MoQ пушит «track catalog» вместо тяги манифеста), а загрузчик сегментов превращается в подписчика на QUIC-stream вместо HTTPS GET-цикла. Всё с подсистемы 3 и далее остаётся прежним.
Где здесь Фора Софт
Мы поставляли плеерные интеграции во всех формах, которые описывает эта статья: hls.js и Shaka в веб-продукте, AVPlayer в iOS и ExoPlayer в Android в мобильном компаньоне, и per-platform нативные оболочки на Tizen, webOS и Roku для OTT-клиентов. Команды, поставляющие самые чистые стеки, относятся к семи подсистемам как к контракту – один ABR-контроллер, один менеджер буфера, один EME-мост – и пишут вокруг них платформенные шимы, а не переписывают семь подсистем с нуля на каждом устройстве. Этот паттерн мы использовали в OTT-вещании, воспроизведении записей в телемедицине, replay-лекциях в e-learning, консолях просмотра в видеонаблюдении и в плеерах записанных конференций внутри WebRTC-стеков, где запись потом перекодируется в LL-HLS для replay.
Типичные ловушки, в одном абзаце
Две ловушки ловят каждую новую плеерную команду. Первая – считать, что семь подсистем – это семь JavaScript-классов. Это не так: это семь обязанностей, и в любом продакшен-плеере минимум две из них размазаны по нескольким файлам, а минимум одна делится с браузером. Вторая – относиться к телеметрии как к фиче второй фазы. Без телеметрии вы не узнаете, работают ли подсистемы 1–6, и стоимость встраивания телеметрии после запуска неизменно в 10 раз выше стоимости встраивания в первую же версию плеера. Сделайте седьмую подсистему ровней остальным шести с первого дня.
Выводы
- Плеер стриминга – это семь подсистем, не один компонент: манифест, загрузчик, ABR, буфер, декодер, DRM, телеметрия.
- Media Source Extensions и Encrypted Media Extensions – два веб-стандарта, связывающие JS-часть с нативной браузерной.
- Managed Media Source в iOS Safari (17.0/17.1, 2023) заменяет классический MSE на устройствах Apple и открывает AirPlay поверх MSE.
- ABR – самая оттюненная единственная часть любого плеера; в продакшене ходят throughput-based, buffer-based (BOLA), hybrid (MPC) и нейронные варианты.
- Телеметрия – startup time, rebuffer ratio, playback failure rate, exit-before-video-start – решает, выглядят ли остальные шесть подсистем здоровыми или сломанными.
- Нативные плееры (AVPlayer в iOS, ExoPlayer в Android, SDK smart-TV) выигрывают по батарее и интеграции, проигрывают по охвату протоколов и observability.
Что почитать дальше
- Media Source Extensions (MSE): как устроен каждый веб-плеер изнутри – подсистема 4 во всех деталях.
- Encrypted Media Extensions (EME): как DRM живёт в браузере – подсистема 6 во всех деталях.
- hls.js подробно – самый используемый JS-плеер, файл за файлом.
- Adaptive bitrate без баззвордов – подсистема 3 во всех деталях.
- Observability плеера и метрики, которые едут в прод – подсистема 7 во всех деталях.
- HLS подробно: m3u8, сегменты, multi-variant playlists – что именно парсит подсистема 1.