Содержание статьи +
- TL;DR
- Зачем это нужно
- Что такое LL-HLS – одним абзацем
- Бюджет задержки: до и после
- Пять механизмов – по одному
- Реальный LL-HLS медиа-плейлист, строка за строкой
- Chunked transfer, версии HTTP и что происходит на проводе
- ABR в LL-HLS: как плеер переключается
- Где сейчас реально находится пол задержки, 2026
- Типичные грабли
- Когда LL-HLS – правильный выбор, а когда – нет
- Где здесь Фора Софт
- Ключевые тезисы
- Что читать дальше
- CTA
Опубликовано: 2026-05-21 · Время чтения: 24 мин · Автор: Николай Сапунов, CEO Фора Софт
Последняя сверка: 2026-05-21 по IETF RFC 8216 (HTTP Live Streaming, август 2017), draft-ietf-pantos-hls-22 (HTTP Live Streaming, второе издание, 1 мая 2026), Apple HLS Authoring Specification for Apple Devices, ревизия 2025-09, доклад Apple WWDC 2025 «What's new in HTTP Live Streaming», ISO/IEC 23000-19:2024 (CMAF), Bitmovin Video Developer Report 2025/26.
TL;DR
Low-Latency HTTP Live Streaming – LL-HLS – это расширение стандартного HLS, которое добавляет пять механизмов, чтобы зритель видел прямую трансляцию с задержкой 2–5 секунд после события, а не 20–30, как в классическом HLS. Эти механизмы: частичные сегменты (тег #EXT-X-PART), подсказки предзагрузки (#EXT-X-PRELOAD-HINT), блокирующая перезагрузка плейлиста (флаг #EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES и query-параметры плеера _HLS_msn / _HLS_part), отчёты по рендинам (#EXT-X-RENDITION-REPORT) и дельта-обновления плейлиста (CAN-SKIP-UNTIL плюс тег #EXT-X-SKIP). Вместе они заменяют цикл «запросил – подождал – повторил» обычного HLS на long-polling: сервер удерживает каждый запрос плейлиста открытым до появления следующего фрагмента медиа и сразу его отдаёт, а плеер успевает запустить следующий long-poll до обработки ответа на предыдущий. Требование HTTP/2 server push, с которого начинался LL-HLS в 2019 году, Apple убрала из спецификации HLS Authoring Specification в ревизии сентября 2023 года; к 2026 году LL-HLS работает поверх обычного HTTP/1.1 с chunked transfer, HTTP/2-стримов или HTTP/3-стримов с chunked-версией CMAF-сегментов, которые может генерировать любой современный пакетизатор.
Зачем это нужно
Обычный HLS – отличный формат для доставки контента через CDN, но ужасный выбор для интерактивных медиа. Сегмент длиной 6 секунд плюс буфер из трёх сегментов дают задержку в 18 секунд до начала воспроизведения – а на практике, с учётом кодирования, сети и плеера, glass-to-glass задержка стабильно держится на уровне 25–30 секунд. Для просмотра фильмов это нормально, но для спортивных ставок, прямых аукционов, обучения с Q&A, видеонаблюдения, телемедицины и live-торговли – катастрофа: реакция зрителя должна попадать в тот же момент, что и событие, а не в его повтор. LL-HLS (LL-HLS) – это протокол, который выбирают, когда нужна экономичность HLS и совместимость с экосистемой Apple, но при этом зритель должен успеть твитнуть про гол во время матча, а не после повтора. Механика здесь тонкая, сбои проявляются неочевидно, а неправильная настройка вместо низкой задержки даёт постоянные перезапуски буфера. Цель этой статьи – сделать каждую строку LL-HLS-списка воспроизводимых сегментов понятной и заранее раскрыть все компромиссы, пока они не превратились в счёт от CDN за весь сезон.
Что такое LL-HLS – одним абзацем
LL-HLS – это стандартный HLS с добавлением пяти тегов и одного нового поведения HTTP. Производитель кодирует прямой эфир так же, как и для обычного HLS, но вместо ожидания шести секунд до публикации полного сегмента пакетизатор разбивает каждый сегмент на 10–30 частичных сегментов (или parts, или чанков в терминологии CMAF) длительностью 200–500 мс и публикует каждый из них сразу после готовности. Теперь медиа-плейлист содержит не только завершённые сегменты вверху, но и части текущего, ещё не завершённого сегмента – внизу. Тег #EXT-X-PART указывает длительность и URI каждого part; другой тег, #EXT-X-PRELOAD-HINT, заранее сообщает плееру URI следующего part’а ещё до его появления. Плеер использует long-poll-запрос – playlist.m3u8?_HLS_msn=42&_HLS_part=7 – со смыслом: «верни мне плейлист, когда в нём появится part 7 сегмента 42». Сервер удерживает этот запрос открытым до тех пор, пока нужный part не будет готов, после чего мгновенно возвращает ответ. Плеер успевает отправить следующий long-poll-запрос ещё до обработки текущего ответа. В результате вместо ритма «остановка – запрос» получается непрерывный поток медиа, а задержка от экрана до экрана (glass-to-glass) снижается с 25 секунд до 2–5.
Протокол представили на WWDC 2019 как Apple Low-Latency HLS – расширение существующей спецификации HLS. Первоначальный дизайн 2019 года полагался на HTTP/2 server push для доставки частей потока; индустрия критиковала его из-за слабой поддержки коммерческими CDN в продакшене. В ревизии сентября 2023 года Apple убрала требование HTTP/2 push и заменила его механизмом preload-хинтов, описанным ниже. Сейчас спецификация является частью того же Internet-Draft, что и остальная часть HLS, – draft-pantos-hls-rfc8216bis-22, опубликованного 1 мая 2026 года, – а для устройств Apple нормативные требования к ней прописаны в HLS Authoring Specification ревизии 2025-09.
Бюджет задержки: до и после
Самый наглядный способ понять, как работает LL-HLS, – сравнить его с обычным HLS, разместив рядом бюджет задержки и наблюдая, как уменьшается длительность каждого сегмента потока.
У типичной прямой трансляции на обычном HLS задержка складывается из трёх компонентов. Кодировщик формирует сегменты по шесть секунд – до того как первый байт сегмента 42 попадёт на origin-сервер, проходит шесть секунд реального времени. Обновление плейлиста требует одного round-trip за каждый target-duration, то есть в среднем – половина target-duration ожидания между появлением нового сегмента и моментом, когда плеер о нём узнаёт; для шестисекундного target – это 3 секунды. Буфер воспроизведения по конвенции составляет 3× target-duration, чтобы плеер мог компенсировать сетевой джиттер без ребуферинга – ещё 18 секунд. Добавьте около секунды на HTTP-оверхед – и получится примерно 28 секунд glass-to-glass. В продакшене замеры показывают 20–30 секунд.
LL-HLS переписывает каждую строку.
| Слагаемое задержки | Обычный HLS (сегменты 6 с) | LL-HLS (сегменты 6 с, parts 200 мс) |
|---|---|---|
| Кодировщик | 6.0 с (целый сегмент) | 0.2 с (один part) |
| Обновление плейлиста | 3.0 с (половина target-duration) | 0.0 с (blocking reload возвращает мгновенно) |
| Буфер воспроизведения | 18.0 с (3× target-duration) | 0.6–1.2 с (3–6 parts) |
| HTTP-оверхед | 1.0 с | 0.4 с (pipelined) |
| Итого glass-to-glass | ~28 с | ~2.2–3.0 с |
Строка «Кодировщик» падает с 6 с до 200 мс, потому что пакетизатор публикует part сразу после его готовности, не дожидаясь полного сегмента. Строка «Обновление плейлиста» обнуляется: сервер держит long-poll открытым до появления part’а и возвращает ответ в тот же момент, как только он появляется – round-trip на опрос не требуется. Буфер сокращается с 3× target-duration до 3–6 part’ов, потому что минимальной единицей, с которой работает плеер, теперь стал part, а не сегмент. HTTP-оверхед уменьшается вдвое благодаря конвейеризации запросов. Математика проста: 0.2 + 0.0 + 0.6 + 0.4 = 1.2 с – это протоколная задержка, плюс 1–2 с на пайплайн кодировщика и предзагрузку декодера – итого LL-HLS попадает в диапазон 2–3 с, который и подтверждают замеры в продакшене в экосистеме Apple.
Пять механизмов – по одному
LL-HLS – это не одна новая технология, а пять новых компонентов, которые приносят пользу только в совокупности. Пропустите хотя бы один – и получите более медленную версию LL-HLS, которая всё ещё будет называться LL-HLS в конфигурации. Представьте каждый механизм как отдельную машину – и вся система станет понятной.
Механизм 1 – Частичные сегменты (`#EXT-X-PART`)
Частичный сегмент, или part, – это срез продолжительностью 200–500 мс ещё не завершённого сегмента, доступный как отдельный HTTP-ресурс. Пока кодировщик формирует сегмент 42, пакетизатор уже разбивает и публикует части 1, 2, 3 – каждую в виде отдельного файла (или диапазона байтов внутри файла сегмента). Медиа-плейлист добавляет для каждой завершённой части новый тег:
#EXT-X-PART:DURATION=0.20000,URI="seg42-p1.m4s",INDEPENDENT=YES
#EXT-X-PART:DURATION=0.20000,URI="seg42-p2.m4s"
#EXT-X-PART:DURATION=0.20000,URI="seg42-p3.m4s"DURATION – длительность part в секундах, указанная десятичным числом. Спецификация требует, чтобы сумма длительностей всех parts сегмента точно соответствовала продолжительности #EXTINF этого сегмента после его закрытия. URI указывает на part относительно плейлиста, так же, как и URI сегмента. Опциональный атрибут INDEPENDENT=YES помечает part, начинающийся с I-кадра – это единственный тип part, который плеер может использовать в качестве точки переключения ABR или первого кадра после операции seek; спецификация требует наличия хотя бы одного независимого part на сегмент, а Apple Authoring Specification рекомендует размещать независимый part не реже одного раза в секунду.
Второй новый тег объявляет политику частей в начале плейлиста:
#EXT-X-PART-INF:PART-TARGET=0.2PART-TARGET – целевая длительность part'а в секундах. Плеер использует это значение, чтобы заранее определить размер буфера; оно должно быть не меньше, чем самый длинный part в плейлисте. Apple Authoring Specification требует PART-TARGET ≤ 0.33 (333 мс) для режима ультранизкой задержки и PART-TARGET ≤ 1.0 для расслабленного режима. 200 мс – безопасное значение по умолчанию, 300 мс – безопасный верхний предел.
Выбор PART-TARGET – главный рычаг управления задержкой в LL-HLS. Чем меньше parts – тем ниже задержка, но больше запросов; чем больше parts – тем выше задержка, но меньше запросов. Арифметика проста: шестисекундный сегмент с частями по 200 мс даёт 30 частей, поэтому в стриме из 5 рендиций получается 150 запросов на 6 секунд (25 в секунду) вместо 5 запросов на 6 секунд (менее одного в секунду). Дизайн ключей кэширования на origin и CDN должен это выдерживать.
Механизм 2 – Подсказки предзагрузки (`#EXT-X-PRELOAD-HINT`)
После того как плеер забирает все части из текущего плейлиста, он всё ещё не знает, где будет находиться следующая часть, пока не обновит плейлист. Подсказка preload сообщает об этом заранее:
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="seg42-p4.m4s"TYPE=PART объявляет, что следующим, что плееру нужно запросить, является часть (part). Плеер сразу отправляет обычный HTTP GET по этому URI. Сервер удерживает запрос открытым – файл ещё не готов, – и как только кодировщик публикует часть, сервер начинает передавать байты обратно по уже установленному соединению: через HTTP/1.1 с chunked transfer encoding, HTTP/2-стрим или HTTP/3-стрим. С точки зрения плеера – он запросил следующую часть, и она пришла. Круговой путь «прочитать плейлист, найти URI, запросить часть, дождаться ответа» сжимается до одного уже открытого соединения.
Preload-хинты заменили HTTP/2 server push – изначальный подход 2019 года. HTTP/2 push оказался слишком сложным для масштабирования в CDN, поскольку push-ответы обходили кеширование в коммерческих CDN; Apple убрала требование к нему в ревизии спецификации HLS Authoring Specification от сентября 2023 года. Ревизия сентября 2025 года оставляет preload-хинты единственным нормативным способом доставить следующий part плееру до появления его URI в обновлённом плейлисте. Статьи, в которых до сих пор утверждается, что LL-HLS требует HTTP/2 push, написаны до этого изменения и устарели.
TYPE=MAP – вторая форма, используется для предзагрузки следующего CMAF-init-сегмента, когда кодировщик меняет параметры кодирования между сегментами. На практике в установившемся стриме это срабатывает редко и важно в основном на границах ABR-переключения.
Механизм 3 – Блокирующая перезагрузка плейлиста
Плеер запрашивает медиа-плейлист не по фиксированному расписанию, а с помощью long-polling, указывая часть, до которой сервер должен подождать:
GET /720p/playlist.m3u8?_HLS_msn=42&_HLS_part=7 HTTP/1.1
Host: edge.example.comДва зарезервированных query-параметра – _HLS_msn (номер медиапоследовательности, который плеер ожидает получить в ответе) и _HLS_part (индекс части внутри этого сегмента) – являются директивами доставки, определёнными в спецификации. Сервер анализирует их и действует следующим образом: если плейлист с 7-й частью 42-го сегмента уже доступен – возвращает его немедленно; если нет – удерживает запрос открытым до появления нужной части, после чего возвращает плейлист; если ожидание превышает 3× target-duration – возвращает имеющийся плейлист с указанием, что данные продолжат поступать.
Это поведение включается при выполнении двух условий. Первое – мультивариантный плейлист (или сам медиа-плейлист в более старых конфигурациях) должен указывать на готовность сервера блокировать запрос:
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=0.7,HOLD-BACK=6CAN-BLOCK-RELOAD=YES – однозначный сигнал о том, что long-poll-запросы с _HLS_msn обрабатываются. PART-HOLD-BACK – минимальное расстояние от live edge в секундах, с которого плеер должен начинать воспроизведение; обычно составляет 3× PART-TARGET. HOLD-BACK – fallback на уровне сегментов для клиентов, не поддерживающих parts; спецификация рекомендует значение в шесть секунд.
Второе условие – сервер действительно поддерживает long-poll. Именно здесь коммерческие сборки начинают давать сбои: многие origin-серверы сразу возвращают содержимое с диска, игнорируя _HLS_msn, и рассчитывают на то, что плеер повторит запрос. В результате получается polling-цикл, замаскированный под LL-HLS, и задержка возвращается к уровню обычного HLS. Apple Authoring Specification требует, чтобы сервер, объявляющий поддержку CAN-BLOCK-RELOAD=YES, действительно выполнял блокировку. Перед тем как объявить развертывание совместимым, обязательно проведите полную проверку через mediastreamvalidator и Apple hlsreport.
Механизм 4 – Отчёты по рендициям (`#EXT-X-RENDITION-REPORT`)
Плеер, который хочет переключиться с 720p на 1080p посреди прямой трансляции, не может использовать состояние blocking-reload плейлиста 720p, чтобы определить текущую позицию в 1080p. Без дополнительной информации ему пришлось бы отправить новый GET-запрос к медиа-плейлисту 1080p, распарсить его, найти последний sequence/part – и только после этого запустить long-poll. Такой round-trip занимает сотни миллисекунд и часто приводит к односегментному ребуферингу на границе переключения.
Rendition-отчёты устраняют эту проблему, привязывая текущее состояние каждой соседней рендиции к каждому медиа-плейлисту:
#EXT-X-RENDITION-REPORT:URI="../1080p/playlist.m3u8",LAST-MSN=42,LAST-PART=8
#EXT-X-RENDITION-REPORT:URI="../480p/playlist.m3u8",LAST-MSN=42,LAST-PART=8
#EXT-X-RENDITION-REPORT:URI="../360p/playlist.m3u8",LAST-MSN=42,LAST-PART=8Каждый отчёт содержит URI соседнего медиа-плейлиста, его последний sequence number и индекс части. Плеер, переключающийся на 1080p, читает отчёт о rendition’е для 1080p прямо из имеющегося у него плейлиста 720p и сразу отправляет запрос playlist.m3u8?_HLS_msn=42&_HLS_part=9 на 1080p – без зондирующего round-trip, без ребуферинга.
Apple Authoring Specification требует, чтобы каждая LL-HLS (LL-HLS) рендия включала rendition-отчёты для всех соседних видео-, аудио- и субтитровых рендий той же группы вариантов. В стриме с 5 видео-рендициями, 3 аудио- и 2 субтитровыми рендиями каждый медиа-плейлист содержит 9 строк rendition-отчётов. Это означает, что плеер получает всю необходимую информацию единовременно вместе с плейлистом, а не выполняет 9 дополнительных long-poll запросов при каждом переключении.
Механизм 5 – Дельта-обновления плейлиста (`CAN-SKIP-UNTIL` + `#EXT-X-SKIP`)
Пятый механизм – то, что не позволяет самому плейлисту расти без ограничений. Плейлисты обычного HLS для прямых трансляций обычно содержат скользящее окно продолжительностью в несколько сотен секунд: за его пределами сегменты удаляются из нижней части файла, и он остаётся компактным. LL-HLS делает плейлист значительно более объёмным: при каждом обновлении публикуются также и части снизу, а скользящее окно приходится делать длиннее, если плеер должен поддерживать перемотку назад или восстановление после длительного перебуферинга. Без вмешательства медиа-плейлист LL-HLS может достигать десятков килобайт на одно обновление, а при 25 обновлениях в секунду на рендицию нагрузка на канал становится значительной.
Дельта-обновления решают эту проблему. Сервер сообщает границу пропуска – самый старый сегмент, который плеер может пропустить, – в #EXT-X-SERVER-CONTROL:
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,CAN-SKIP-UNTIL=36.0,PART-HOLD-BACK=0.7CAN-SKIP-UNTIL=36.0 означает, что сервер может отбросить любой сегмент, возраст которого превышает 36 секунд от live edge. Согласно спецификации Apple Authoring, требуется, чтобы CAN-SKIP-UNTIL было не менее 6× target-duration; при целевом значении 6 секунд это даёт порог в 36 с. Плеер активируется, добавляя _HLS_skip=YES к своему URL для long-poll.
GET /720p/playlist.m3u8?_HLS_msn=42&_HLS_part=7&_HLS_skip=YES HTTP/1.1Сервер возвращает плейлист с новым тегом вместо пропущенных сегментов:
#EXT-X-SKIP:SKIPPED-SEGMENTS=80Это означает: «следующие 80 сегментов я пропускаю – они у тебя уже есть из предыдущего ответа». Плеер вставляет пропущенный диапазон в своё представление плейлиста, и объём передаваемых данных сокращается на порядок. Семантика остаётся эквивалентной полному плейлисту – меняются только байты в эфире.
CMAF и init-сегменты EXT-X-MAP никогда не пропускаются, потому что плееру они могут понадобиться в любой момент. Discontinuities и date-range’ы, попавшие в пропущенное окно, тоже не пропускаются – сервер обязан их вернуть. Реализации иногда ошибаются в обработке discontinuity – в issue-трекере hls.js с конца 2025 года висит регрессия, в которой дельта-обновления теряли discontinuity, необходимую плееру для согласования рекламных маркеров. Прогоняйте mediastreamvalidator -P и Apple hlsreport после каждого мажорного обновления пакетизатора.
Реальный LL-HLS медиа-плейлист, строка за строкой
Вот реалистичный LL-HLS (LL-HLS HLS) медиа-плейлист одного варианта в середине трансляции: один сегмент полностью закрыт, следующий – в процессе загрузки.
#EXTM3U
#EXT-X-VERSION:9
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:41
#EXT-X-PART-INF:PART-TARGET=0.2
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,CAN-SKIP-UNTIL=36.0,PART-HOLD-BACK=0.7,HOLD-BACK=6
#EXT-X-MAP:URI="init.mp4"
#EXTINF:6.000,
seg41.m4s
#EXT-X-PART:DURATION=0.20000,URI="seg42-p1.m4s",INDEPENDENT=YES
#EXT-X-PART:DURATION=0.20000,URI="seg42-p2.m4s"
#EXT-X-PART:DURATION=0.20000,URI="seg42-p3.m4s"
#EXT-X-PART:DURATION=0.20000,URI="seg42-p4.m4s"
#EXT-X-PART:DURATION=0.20000,URI="seg42-p5.m4s"
#EXT-X-PART:DURATION=0.20000,URI="seg42-p6.m4s"
#EXT-X-PART:DURATION=0.20000,URI="seg42-p7.m4s"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="seg42-p8.m4s"
#EXT-X-RENDITION-REPORT:URI="../1080p/playlist.m3u8",LAST-MSN=42,LAST-PART=7
#EXT-X-RENDITION-REPORT:URI="../480p/playlist.m3u8",LAST-MSN=42,LAST-PART=7
#EXT-X-RENDITION-REPORT:URI="../360p/playlist.m3u8",LAST-MSN=42,LAST-PART=7Читайте сверху вниз. #EXTM3U объявляет HLS. #EXT-X-VERSION:9 – минимальная версия HLS, которую плеер должен поддерживать; версия 9 – первая, в которой реализован полный набор LL-HLS (LL-HLS)-тегов, включая CAN-SKIP-UNTIL и #EXT-X-SKIP; для исходного LL-HLS 2019 без дельта-обновлений хватало версии 6. #EXT-X-TARGETDURATION:6 – никакой сегмент не превышает 6 секунд. #EXT-X-MEDIA-SEQUENCE:41 – сегмент 41 – первый закрытый сегмент в этом срезе плейлиста. #EXT-X-PART-INF:PART-TARGET=0.2 объявляет целевую длительность part. #EXT-X-SERVER-CONTROL рекламирует поддержку long-poll, границы пропуска, hold-back на уровне part и на уровне сегмента. #EXT-X-MAP указывает на CMAF init-сегмент.
Затем следует закрытый сегмент: #EXTINF:6.000, и seg41.m4s. Далее – 7 частей активного сегмента 42, каждая длительностью 200 мс и со своим URI. Часть 1 содержит INDEPENDENT=YES, поскольку начинается с I-кадра; остальные – части с P-кадрами, которые плеер сможет декодировать только после получения части 1.
Дальше – preload-хинт: TYPE=PART и URI, по которому будет доступен part 8 после его появления. Плеер уже сейчас отправляет HTTP GET-запрос по этому URI; сервер удерживает ответ до публикации part 8.
И наконец, три отчёта о рендерах для соседних разрешений: 1080p, 480p и 360p. Каждый из них сообщает последний номер последовательности и индекс части, достигнутые соответствующей рендерацией; переключение ABR может получать новый вариант напрямую, без зондирующего цикла.
Когда плейлист обновится, сегмент 42 закроется (#EXTINF:6.000, + seg42.m4s), снизу появятся первые части сегмента 43, preload-указание сместится на часть 1 сегмента 43, а отчёты о rendition продвинутся. Старые сегменты будут постепенно исчезать из нижней части файла по мере сдвига окна. С _HLS_skip=YES сервер вернёт новое состояние минус #EXT-X-SKIP:SKIPPED-SEGMENTS=N вместо сегментов, которые плеер уже получил.
Chunked transfer, версии HTTP и что происходит на проводе
LL-HLS Long Polling (LL-HLS) использует long-poll поверх обычного HTTP. Первоначальный дизайн 2019 года предполагал доставку частей данных через HTTP/2 server push, но это требование больше не актуально. В 2026 году картина в продакшене выглядит примерно так: около половины трафика – это HTTP/1.1 с chunked transfer encoding, треть – HTTP/2-стримы, остальное – HTTP/3 поверх QUIC. При этом HTTP/3 растёт быстрее всех, поскольку естественно интегрируется с тем же QUIC-стеком, который лежит в основе MoQ.
Механика работы по проводу немного отличается в зависимости от версии HTTP, но семантика остаётся одинаковой. В HTTP/1.1 сервер удерживает long-poll, после чего начинает отвечать с Transfer-Encoding: chunked, отправляя каждый фрейм части отдельным чанком по мере его появления от кодировщика. В HTTP/2 и HTTP/3 сервер открывает стрим и передаёт data-фреймы по мере их поступления; оба протокола поддерживают такое поведение, поскольку рассматривают тело ответа как последовательность фреймов, а не как единый буфер. Смысл одинаков во всех версиях: плеер начинает декодировать первый байт части сразу после его получения, ещё до того, как вся часть будет передана целиком.
CMAF-чанки – это аналог LL-HLS-частей с точки зрения кодирования. CMAF-чанк представляет собой минимальную единицу, способную к независимому декодированию, которую может сформировать CMAF-кодировщик. На практике пакетизаторы создают один чанк на одну часть, и в профессиональной среде термины «чанк» и «часть» часто используются как синонимы. Полный цикл выглядит так: кодировщик генерирует CMAF-чанк → пакетизатор оборачивает его в адресуемый HTTP-ресурс → медиа-плейлист публикует #EXT-X-PART, ссылающийся на этот ресурс → сервер передаёт его через chunked transfer или HTTP/2/3-стримы → плеер начинает декодирование сразу после получения первого кадра. Современные пакетизаторы – Wowza, AWS MediaPackage, Bitmovin Live, Mux Live, Norsk, Unified Streaming, Shaka Packager – по умолчанию выпускают LL-HLS в формате CMAF с одним чанком на часть. Формат CMAF стандартизирован в ISO/IEC 23000-19:2024; рекомендации по использованию LL-HLS на основе CMAF изложены в Apple Authoring Specification §3 и DASH-IF Low-Latency Modes For DASH.
ABR в LL-HLS: как плеер переключается
ABR-переключение в обычном HLS работает просто: когда плеер решает перейти с 720p на 1080p, он загружает медиа-плейлист нового варианта, определяет границу сегмента, скачивает новый init-сегмент, если он изменился, и продолжает воспроизведение. В LL-HLS та же логика, но с двумя дополнительными ограничениями.
Во-первых, плеер может переключиться только на независимом part'е – том, чья строка #EXT-X-PART несёт INDEPENDENT=YES. Независимые parts начинаются с I-frame и могут декодироваться без отсылки к предыдущим parts. Apple Authoring Specification рекомендует не реже одного независимого part'а в секунду; это даёт плееру точку переключения каждые 5 parts при PART-TARGET=0.2. P-frame parts не могут быть первым part'ом, который плеер декодирует на новом варианте.
Во-вторых, плеер использует rendition-отчёты, чтобы избежать зондирующего round-trip. При наличии rendition-отчётов последовательность переключения выглядит так: оценщик полосы решает перейти с 720p на 1080p; плеер считывает rendition-отчёт для 1080p из текущего плейлиста 720p (LAST-MSN=42, LAST-PART=7); плеер сразу отправляет long-poll запрос на плейлист 1080p за _HLS_msn=42&_HLS_part=8; как только приходит ответ – скачивает init-сегмент 1080p, если его нет в кэше, и начинает загружать части. Никакого дополнительного зондирования, никаких GET-запросов к плейлисту, возвращающих «вы уже синхронны», никакой задержки на границе сегмента.
Угловой случай – это ситуация, когда временные линии 1080p и 720p расходятся относительно друг друга. CMAF обеспечивает временное выравнивание рендиций, так что для каждого значения media-sequence-number соответствует один и тот же момент реального времени во всех рендициях. Apple Authoring Specification §2.10 делает такое выравнивание обязательным для вариантов одного мультивариантного плейлиста: если upstream-кодировщик дрейфует, переключения ABR будут сопровождаться заметными артефактами. Проверяйте выравнивание с помощью mediastreamvalidator после каждого изменения конфигурации кодировщика.
Где сейчас реально находится пол задержки, 2026
Продакшен-сборки Mux, Wowza, Bitmovin и AWS, которые сегодня доставляют LL-HLS (LL-HLS), сообщают о задержке «от экрана до экрана» в 2–3 секунды для зрителей в одном регионе на современных устройствах. Демонстрации Apple на WWDC 2025 показали задержки менее двух секунд в контролируемой среде на iPhone 15 с iOS 17 при использовании chunked-HTTP Live Streaming (chunked-HTTP Live Streaming) в origin-сервере за edge-сетью iCloud. В реальных условиях среднее значение немного выше – 3–5 секунд, поскольку факторы, не покрываемые LL-HLS (глубина пайплайна кодировщика, предзагрузка декодера, джиттер на последнем километре), всё равно остаются.
Цифры конкретны. Опубликованный замер Mux 2024 года показывает, что у LL-HLS 4.0 среднее время glass-to-glass составляет 3,2 с (медиана), 6,1 с (p95) и 9,4 с (p99) на 35 000 сессий, в то время как у обычного HLS в тех же условиях среднее значение – 22,0 с. Замеры Wowza 2025 года – 5–6 с для одного клиента на Safari на iPhone. Bitmovin сообщает о 3–4 с в продакшене своих заказчиков, при этом нижняя граница – 1,5 с, достижимая только при тонкой настройке пайплайна (B-кадры отключены, GOP = 1 секунда, сегмент – 2 секунды, parts – 200 мс). Реализации уровня спецификации от Apple на Apple TV и iOS приближаются к 2 с, если origin находится в одном сетевом регионе с клиентом.
Причина, по которой задержка в продакшн-среде остаётся выше 2 секунд, – в том, что LL-HLS не может ускорить кодировщик быстрее, чем его пайплайн, декодер – быстрее, чем его предзагрузка, а сеть – быстрее, чем RTT × джиттер. Две секунды, которые LL-HLS экономит по сравнению с классическим HLS, – это выигрыш за счёт обновления плейлиста и буфера, которые не ограничены физическими законами. Оставшиеся 2–3 секунды – это реальный фундаментальный предел: 1 секунда на пайплайн кодировщика (GOP, буферизация для B-frame-референсов, CABAC-энтропия и мультиплексирование чанка), 200–400 мс на предзагрузку декодера, 100–300 мс на last-mile RTT и 200–500 мс на оверхед CDN/origin. Чтобы опуститься ниже 2 секунд, нужен WebRTC – но за это придётся заплатить потерей экономии на CDN, которая делает HLS дешёвым в эксплуатации.
Типичные грабли
Пять механизмов описывают, что такое LL-HLS. Грабли показывают, что ломается в продакшене, когда один из механизмов настроен неправильно. Каждая команда, разрабатывающая LL-HLS, сталкивается с подмножеством этих проблем.
«Грабли – origin отвечает мгновенно и игнорирует _HLS_msn. Origin рекламирует CAN-BLOCK-RELOAD=YES, но на деле long-poll не реализован. Плеер делает опрос; сервер возвращает текущий плейлист; плеер снова опрашивает – задержка остаётся на уровне обычного HLS, хотя плейлист формально совместим с LL-HLS. Проверка: отправить запрос с _HLS_msn, установленным значительно вперёд относительно live edge, и замерить, сколько времени сервер его держит. Ответ должен прийти в пределах ±50 мс от момента публикации запрошенной части, а не с задержкой, равной интервалу опроса плеера.»
«Грабли – PART-TARGET выставлен слишком высоко. Некоторые пакетизаторы по умолчанию ставят PART-TARGET в 1000 мс или 500 мс, чтобы разгрузить origin. Пол задержки сдвигается соответственно: PART-HOLD-BACK – это 3× PART-TARGET, поэтому секундный part даёт минимум 3 с обязательного hold-back поверх пола кодировщика и декодера. Продакшен LL-HLS использует 200-мс parts; 500 мс – это регрессия от дефолта.»
«Грабли – слишком редкие независимые части. Apple Authoring Specification рекомендует использовать один независимый part на каждую секунду реального времени. Некоторые кодировщики по умолчанию ставят один part на сегмент (раз в 6 секунд), из-за чего ABR-переходы вынуждены ждать границы сегмента; задержка при переключении составляет целый сегмент, а не один part. Настройте кодировщик на I-кадр раз в секунду; проверяйте ffprobe -show_packets после изменения конфигурации.»
«Грабли – CDN cache-key игнорирует _HLS_msn / _HLS_part. CDN, кеширующий плейлист без этих query-параметров в ключе, отдаёт устаревший плейлист при каждом long-poll. Фикс – включить _HLS_msn, _HLS_part и _HLS_skip в cache-key CDN и установить для плейлиста Cache-Control: max-age=1 (или 0), чтобы CDN перетягивал его при каждом запросе. Akamai, Cloudflare, Fastly и AWS CloudFront – все поддерживают такую настройку, но её нужно явно задавать при каждом деплое.»
«Грабли – разрыв (discontinuity), выпавший из дельта-обновления. Когда сервер возвращает #EXT-X-SKIP:SKIPPED-SEGMENTS=N, любые #EXT-X-DISCONTINUITY или #EXT-X-DATERANGE (рекламный маркер SCTE-35) внутри пропущенного диапазона должны остаться в ответе. Некоторые версии пакетизаторов их тихо теряют. В трекере hls.js с конца 2025 года висит регрессия ровно об этом. Прогоняйте mediastreamvalidator -P после каждого обновления пакетизатора.»
«Грабли – старый плеер опрашивает плейлист без _HLS_msn. Legacy-плеер, не поддерживающий LL-HLS (LL-HLS), отправляет обычный GET-запрос к тому же URL медиа-плейлиста. Сервер должен по-прежнему возвращать валидный HLS-плейлист – расширения LL-HLS должны корректно деградировать, и плеер просто проигнорирует LL-HLS-теги. Однако многие серверы оборачивают плейлист в CMAF-чанки, что сбивает с толку плееры, не поддерживающие LL-HLS; проверяйте mediastreamvalidator на обоих профилях перед релизом.»
«Грабли – длительности EXT-X-PART не суммируются в #EXTINF при закрытии сегмента. Спецификация требует, чтобы сумма длительностей частей точно соответствовала #EXTINF сегмента с точностью до микросекунды. Дрейф кодировщика даёт 5.9999 вместо 6.0000 – одни плееры принимают такое значение, другие отвергают; в продакшене заставьте кодировщик выдавать точные длительности и проверяйте их с помощью mediastreamvalidator.»
Когда LL-HLS – правильный выбор, а когда – нет
LL-HLS – подходящий протокол, если вы хотите использовать экономику CDN для HLS, транслируете контент на устройства Apple и готовы принять задержку в 2–5 секунд. Такой подход охватывает большинство кейсов live OTT с аудиторией свыше 100 000 одновременных зрителей: прямые трансляции спортивных событий без интеграции со ставками, новостные эфиры, концерты, live-мероприятия с шопингом, где основной формой взаимодействия является чат, образовательные занятия с отложенными вопросами и ответами, а также просмотр записей с камер видеонаблюдения.
LL-HLS – неправильный выбор в двух направлениях. Вверх – когда нужна задержка ниже двух секунд (ставки на спорт, прямые аукционы, real-time-игры, телемедицина с синхронным видео, видеоконференции) – ответом станут WebRTC delivery и Media over QUIC, а LL-HLS оставит заметную задержку в одну секунду между действием и реакцией. Вниз – когда задержка выше 10 секунд не критична (длинные VOD, повторы, видео-подкасты, архив) – простой HLS или MPEG-DASH проще, дешевле и лучше работают с кешированием. LL-HLS требует от CDN обработки большого числа long-poll-запросов; если низкая задержка не нужна, эти расходы тоже не нужны.
Не-Apple-альтернатива в той же полосе 2–5 секунд – LL-DASH поверх chunked-CMAF – те же CMAF-чанки, произведённые и упакованные один раз, которые доставляются как HLS на устройства Apple, так и как DASH на всё остальное. CMAF делает это практичным без удвоения хранилища; рекомендуемый кластерным брифом паттерн на 2026 год – «LL-HLS для iOS/Safari, LL-DASH для Chrome/Edge/Firefox/Android, один набор CMAF-чанков под оба протокола». Дерево семейства протоколов показывает, где находится каждый протокол.
Где здесь Фора Софт
Мы поставляли LL-HLS в платформы прямого e-learning, OTT-сервисы, телемедицинские системы триажа и live-торговлю. Наша инженерная команда стриминга рассматривает пять описанных механизмов как единую систему: пайплайн кодировщика, выдача пакетизатора, поведение long-poll на origin, cache-key’и CDN и ABR-алгоритм плеера настраиваются совместно. Причина в том, что сбои в продакшене чаще всего возникают на стыках между слоями, а не внутри одного из них. И наоборот: мы помогали клиентам понять, что их задача на самом деле требует WebRTC, и не использовать LL-HLS для субсекундных сценариев. Чёткое определение границ ответственности с самого начала экономит три месяца на разборе вопросов «почему всё ещё буферит».
Ключевые тезисы
- LL-HLS заменяет цикл «опросил – подождал» обычного HLS пятью механизмами, превращающими плейлист в long-poll-таргет, а сегмент – в последовательность 200-миллисекундных частей.
- Эти пять механизмов – parts, preload-хинты, blocking reload, rendition reports и дельта-обновления – работают как единая система: если отключить любой из них, получится обычный HLS с лишними тегами.
- Поддержка HTTP/2 server push была удалена начиная с ревизии Apple HLS Authoring Specification от сентября 2023 года; её заменили preload-хинты.
- Продакшен-задержка «от стекла до стекла» в 2026 году составляет 2–5 секунд; задержка ниже 2 секунд требует WebRTC или Media over QUIC, а не LL-HLS.
- CMAF-чанки и LL-HLS-parts – это одна и та же единица на уровне сети; один origin, поддерживающий chunked CMAF, может обслуживать как LL-HLS, так и LL-DASH.
- Основной сценарий сбоя в продакшене – origin, который заявляет о поддержке CAN-BLOCK-RELOAD=YES, но на деле не реализует long-poll; проверку совместимости нужно проводить сквозную, вплоть до объявления.
Что читать дальше
- HLS подробный разбор: m3u8, сегменты, мультивариантные плейлисты – фундамент, на котором строится LL-HLS (LL-HLS).
- LL-HLS (LL-HLS) и low-latency CMAF: chunked encoding на практике – аналог Apple в той же временной полосе 2–5 с.
- Как выбрать протокол доставки в 2026: дерево решений – когда LL-HLS (LL-HLS) – правильный выбор, а когда – нет.
CTA
- Поговорить с инженером по стримингу – чтобы выбрать оптимальную форму (LL-HLS, LL-DASH, WebRTC, MoQ) под ваши цели по задержке и бюджет на CDN.
- Посмотреть наши кейсы – live-обучение, OTT, телемедицина, live-shopping.
- Скачать – Чеклист готовности LL-HLS (2026) – 25 пунктов, которые каждая команда должна проверить перед запуском LL-HLS-сборки в продакшен.