Субтитры и аудиодорожки: WebVTT, IMSC, мультиязычное аудио

Автор: Николай СапуновОбновлено: август 202631 мин чтения
Содержание статьи +

Кратко

Субтитры и несколько аудиодорожек живут в том же манифесте, что и видео, но описываются, сегментируются и доставляются отдельным набором тегов – о которых большинство инженеров узнаёт лишь тогда, когда глухой зритель пишет жалобу или французская аудитория не может найти дубляж. WebVTT – это «лингва франка» веб-субтитров и единственный текстовый формат, который Apple до сих пор требует в HLS в виде сегментированного plain-text; IMSC1 – это broadcast-уровень, упакованный в фрагментированный MP4, единственный TTML-профиль, разрешённый CMAF, и единственный путь к цветным, позиционированным, иллюстрированным субтитрам, которые переживут строгий пакаджинг. Несколько аудиодорожек – оригинал, дубляж, тифлокомментарий, режиссёрский комментарий, downmix-стерео, полноценный 5.1 или Dolby Atmos – объявляются как группа EXT-X-MEDIA в HLS или параллельные AdaptationSet в DASH, и именно атрибуты этих тегов решают, что зазвучит в Париже по умолчанию, что появится в настройках для пользователя со скринридером и не схлопнется ли ваш Atmos-мастер в немое стерео на Roku 2018 года. Эта статья проходит по форматам, разметке манифеста, дисциплине язык/доступность и тем продакшен-решениям, от которых зависит, поедут ли субтитры и аудио в продакшен рабочими – или поломанными.

Почему это важно

Субтитры и мультиязычное аудио – это часть стриминга, которая определяет, можно ли продукт вообще выпустить на регулируемом рынке, удобен ли он для людей с потерей слуха или зрения и сконвертирует ли маркетинговая кампания в новом регионе. В США FCC, в ЕС Акт о доступности (EAA), в Великобритании Equality Act, в Австралии Broadcasting Services Act – все требуют субтитрования для подпадающих под регулирование видеосервисов; тифлокомментарий обязателен для нескольких категорий премиум-контента; платформенные сертификации Apple, Roku, Samsung и Google Play блокируют публикацию приложения при неправильной разметке доступности в манифесте. Ничего из этого не выглядит привлекательно в бэклоге, и почти ничего не попадает в план релиза до первого запуска в франкоязычной стране, первой проверки на доступность или первого отзыва в один балл от слепого пользователя. Эта статья даёт нетехническим лидам достаточно механики, чтобы спланировать работу, а инженерным – точные теги, атрибуты и подводные камни, от которых зависит, дойдут ли субтитры и дубляж до того зрителя, которому они нужны.

Почему субтитры и мультиаудио – это отдельный тип трека

Любой стриминговый манифест описывает три семейства медиа: картинку, звук и текст, накладываемый на картинку. Картинка живёт в видеорендиции; звук – в одной или нескольких аудиорендициях; текст – субтитры и captions – в нуле или нескольких текстовых рендициях. Все три семейства разделяют общий таймлайн, но не один файл. 4K HEVC-сегмент видео не содержит ни аудио, ни субтитров. Многоязычная дублированная аудиодорожка – это свой собственный сегментированный файл. Французские closed captions – свой. Манифест – это то, что сшивает всё это в плеере.

Это разделение сделано осознанно. Энкодер производит картинку один раз и переиспользует её для каждого рынка, где выходит шоу. Аудиокоманда производит оригинальный мастер плюс дубляж под каждый язык. Команда доступности производит закадровые субтитры на языке оригинала, переводные субтитры под каждый рынок, дорожку тифлокомментария для незрячих и видеоналожение с сурдопереводом там, где этого требует регулятор. Если всё это запекать в видеопоток, каждый рынок означал бы пересжатие картинки. Хранить отдельно – единственный способ, при котором сходится математика.

Удобная аналогия: стриминговый манифест – это меню в ресторане, а не одно блюдо. Картинка – это основное блюдо; каждая аудиорендиция – это вино в пару; каждый трек субтитров – карточка-аннотация на столе. Плеер читает меню, спрашивает зрителя – или угадывает по системному языку и настройкам доступности – и заказывает только то, что нужно. Кухня, пакаджер и CDN никогда не собирают всё это в одну тарелку; они отдают плееру только те позиции, которые он попросил.

Структурное следствие в том, что манифест несёт плотные метаданные о каждой текстовой и аудиорендиции: какой это язык, closed caption (расшифровывает речь плюс несловесные звуковые описания для глухих) или обычные subtitles (переводит речь для слышащих зрителей в иноязычном рынке), является ли это тифлокомментарием, является ли субтитр forced (должен показываться всегда, когда показывается видео – типично для иноязычных надписей в кадре и текста на экране), нужно ли его выбрать по умолчанию в данной системной локали. Стоит ошибиться в любом из этих флагов – и зритель, которому нужны субтитры, не увидит ничего, а зритель в Париже услышит английский по умолчанию.

Рис. 1. Стриминговый манифест несёт видео, аудио и текст как три независимые семьи рендиций. Плеер выбирает по одному из каждой – на основе системной локали, настроек доступности и выбора пользователя. Картинка кодируется один раз; аудио и текст варьируются по рынкам.

WebVTT: формат, который понимает каждый веб-плеер

WebVTT – Web Video Text Tracks – это формат субтитров и captions от W3C Timed Text Working Group для открытого веба. Это plaintext-формат, который любой современный браузер парсит нативно через элемент <track>, и это единственный формат subtitles, который HLS допускает в виде plaintext-сегментов (не fMP4). WebVTT-файл маленький, человекочитаемый и тривиально редактируется – те же качества, которые сделали .srt популярным двадцать лет назад, плюс стандартизация, благодаря которой браузеры и пакаджеры одинаково понимают, что значит каждая cue.

Минимальный WebVTT-файл выглядит так:

WEBVTT

00:00:03.000 --> 00:00:06.500
Добро пожаловать на брифинг.

00:00:06.800 --> 00:00:09.200 line:85% align:middle
[хлопает дверь]
Точно по графику, как обещали.

Файл начинается с magic-заголовка WEBVTT. Каждый блок после заголовка – это cue: время начала, время конца, стрелка между ними и одна или несколько строк текста. Cue живёт от старта до конца на таймлайне; плеер накладывает текст на картинку в этом окне. Опциональные настройки cue после таймстампа – line:85% align:middle в примере – управляют тем, где появится текст и как он будет выровнен; без них плеер использует дефолты (типично – внизу по центру с небольшим отступом). WebVTT поддерживает метки говорящих, базовую стилизацию через инлайн-теги вроде <b> и <i>, а также треки глав и метаданных, которые не имеют отношения к видимым субтитрам.

Для доставки в HLS WebVTT сегментируется. Пакаджер режет полный WebVTT-файл на куски, выровненные по сегментам видео – обычно каждые 6 секунд, иногда 10 – чтобы плеер мог запросить только нужное окно cue и удерживать память в разумных рамках на 4-часовом эфире. Каждый сегмент – это валидный самостоятельный WebVTT-файл со своим заголовком WEBVTT. Чтобы временные метки cue остались привязанными к медиа-таймлайну между сегментами, пакаджер добавляет в каждый сегмент заголовок X-TIMESTAMP-MAP, который привязывает локальное время сегмента к presentation timestamp медиа. Apple HLS Authoring Specification прямо описывает формат: X-TIMESTAMP-MAP=LOCAL:<cue time>,MPEGTS:<media time>. Без этого заголовка cues появляются на экране, но не в то время – типичный баг, когда сторонний инструмент создаёт WebVTT без знания HLS.

WebVTT cues могут нести forced-контент – фразу, которую нужно показать независимо от того, включил ли зритель субтитры, потому что в кадре есть надпись на иностранном языке и аудитории нужен перевод, чтобы следить за сюжетом. HLS-манифест помечает forced-рендицию атрибутом FORCED=YES на её строке EXT-X-MEDIA; сам WebVTT-файл содержит только forced-cues, а не полный трек субтитров.

Чего WebVTT делает плохо: типографическое богатство. Цветной текст на цветном фоне, глифы, которых нет в дефолтном шрифте у зрителя (арабский, CJK, сложные письменности, требующие шейпинга), bitmap-субтитры с уже стилизованной графикой, кадровая точность позиционирования сверх того, что выражают line: и position:. Любая из этих потребностей толкает проект в сторону IMSC1.

IMSC1: формат, который использует broadcast

IMSC1 – TTML Profiles for Internet Media Subtitles and Captions – это профиль TTML (Timed Text Markup Language) от W3C, на котором broadcast и OTT-индустрия стандартизировались для премиум-субтитров. IMSC1 определяет два профиля: Text profile, стилизующий текст в стиле HTML+CSS, и Image profile, в котором каждая cue – это PNG-картинка (путь, используемый в Японии и Корее, где типографика субтитров слишком богата, чтобы её надёжно отрисовал любой текстовый движок). IMSC1 поддерживает цвет cue, заливку фона, обводки и тени, точное позиционирование в процентах или пикселях, ruby-аннотации для CJK и двунаправленную раскладку для иврита и арабского.

IMSC1.0.1 стала W3C Recommendation в 2018; IMSC1.1 в 2020 расширила возможности стилизации; IMSC1.2 – текущая редакция, сохраняющая совместимость с документами IMSC1.1 и поддерживающая современные практики. CMAF – единый формат упаковки для HLS и DASH – принимает только один профиль TTML, и это IMSC1. Если контент упаковывается как CMAF, субтитры – это либо WebVTT, либо IMSC1, третьего не дано.

Структурное отличие от WebVTT в том, что IMSC-контент несётся внутри fragmented MP4-сегментов. Пакаджер оборачивает IMSC XML в боксы MPEG-4 Part 30 (ISO/IEC 14496-30) и производит fMP4-файл с расширением .mp4 или .m4s и кодеком stpp (subtitle/text profile). HLS называет их IMSC Segments; DASH везёт их в AdaptationSet с contentType="application" и codecs="stpp". Apple HLS Authoring Specification требует, чтобы каждый IMSC Segment содержал все семплы субтитров, которые должны быть показаны в течение EXTINF-длительности сегмента, и все определения стилей, на которые ссылается любой семпл сегмента – сегменты независимо парсимы, то же свойство, благодаря которому работают видеосегменты.

Поддержка IMSC в плеерах универсальна на крупных платформах и неравномерна на мелких. iOS и tvOS получили IMSC1 Text profile после WWDC 2017; Android Exoplayer, Shaka Player и большинство нативных Smart TV-плееров добавили его в 2018–2020. hls.js добавил IMSC как плагин, а не дефолт – CMAF-only HLS-поток, в котором только IMSC, упадёт молча на веб-плеерах, в которых плагин не подключён. Прагматичная позиция 2026 года – отгружать WebVTT как универсальный текстовый трек и добавлять IMSC только там, где этого требует типографика или контракт с downstream-платформой.

CEA-608 и CEA-708: in-bitstream «выжившие»

Третье семейство captions выжило в 2026 году не потому, что вокруг него кто-то проектирует новые системы, а потому, что это legacy-формат обмена, который workflow broadcast-субтитрования использует со времён аналога. CEA-608 – оригинальный стандарт line-21 captions для NTSC начала 1980-х: 32 символа в строке, два цвета, три режима подачи (pop-on / paint-on / roll-up), не более одного-двух одновременных сервисов. CEA-708 – современный цифровой ATSC-преемник, принятый в 1998 году, поддерживающий до 63 service-каналов, несколько шрифтов, цвета, прозрачность и более богатое позиционирование. Декодеры 708 обязаны уметь декодировать встроенные 608 captions, поэтому один 708-битстрим несёт и 608-совместимые, и более богатые 708-данные бок о бок.

Для стриминга это важно потому, что captions, произведённые до энкодера – лайв-сервисом, broadcast-фидом, архивным мастером – часто приходят встроенными в H.264 или H.265 видеобитстрим как SEI (Supplemental Enhancement Information) сообщения, переносящие 608 или 708 payload. У пакаджера есть два варианта: оставить captions в видеобитстриме и сказать плееру извлечь их на стороне рендера или вырезать их и переотдать как WebVTT- или IMSC-сайдкары.

HLS-манифест сигнализирует in-bitstream-путь тегом EXT-X-MEDIA с TYPE=CLOSED-CAPTIONS, у которого атрибут INSTREAM-ID называет 608-сервис (CC1–CC4) или 708-сервис (SERVICE1–SERVICE63). Плеер читает значение, вытаскивает captions из SEI внутри сегмента и отрисовывает их. Строка EXT-X-STREAM-INF варианта затем ссылается на closed-captions-группу атрибутом CLOSED-CAPTIONS. Вариант без встроенных captions ставит атрибут в NONE явно; пропустить атрибут легально, но это типичный источник несогласованного поведения плееров.

Sidecar-путь вырезает данные 608/708 на пакаджере и переотдаёт их как WebVTT или IMSC-рендицию, точно как выглядел бы созданный вручную трек captions. Это более чистая позиция для новых сборок – она кладёт каждый трек captions в одно семейство тегов манифеста и даёт пакаджеру шанс нормализовать стилизацию. Минус в том, что captions, созданные на лайв-эфире как line-21 данные 608, теряют точность при конверсии: цвет и позиционирование, которые 708 выражал нативно, в WebVTT приходится аппроксимировать.

Прагматичная позиция 2026 года – оставлять CEA-608/708 в битстриме для ingest из broadcast-источника, а затем переотдавать как WebVTT для плеера. Roku, Smart TV и старые Android-устройства до сих пор читают in-bitstream 608/708 надёжно; веб-плееры предпочитают sidecar. Где позволяет энкодер – отгружайте оба.

Разметка манифеста: как HLS всё это связывает

Многоязычный HLS-манифест с captions – лучшее место увидеть, как всё перечисленное собирается воедино. Пример ниже сокращён для ясности, но легален и достаточно полон, чтобы воспроизвестись в современном hls.js или нативном iOS-плеере.

#EXTM3U
#EXT-X-VERSION:7

# Аудиорендиции — три языка + тифлокомментарий
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-main",NAME="English",
  LANGUAGE="en",DEFAULT=YES,AUTOSELECT=YES,CHANNELS="2",URI="audio/en/main.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-main",NAME="Français",
  LANGUAGE="fr",DEFAULT=NO,AUTOSELECT=YES,CHANNELS="2",URI="audio/fr/main.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-main",NAME="Español",
  LANGUAGE="es",DEFAULT=NO,AUTOSELECT=YES,CHANNELS="2",URI="audio/es/main.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-main",NAME="English (Audio Description)",
  LANGUAGE="en",DEFAULT=NO,AUTOSELECT=NO,CHANNELS="2",
  CHARACTERISTICS="public.accessibility.describes-video",URI="audio/en-ad/main.m3u8"

# Рендиции субтитров — WebVTT для веба, IMSC для премиум-рынков
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English (CC)",
  LANGUAGE="en",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,
  CHARACTERISTICS="public.accessibility.transcribes-spoken-dialog,
                   public.accessibility.describes-music-and-sound",
  URI="subs/en/main.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Français",
  LANGUAGE="fr",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,URI="subs/fr/main.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Français (forcés)",
  LANGUAGE="fr",DEFAULT=NO,AUTOSELECT=NO,FORCED=YES,URI="subs/fr-forced/main.m3u8"

# Видеорендиции — каждая ссылается на группы аудио и субтитров
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2",
  AUDIO="aac-main",SUBTITLES="subs",CLOSED-CAPTIONS=NONE
video/1080p/main.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2",
  AUDIO="aac-main",SUBTITLES="subs",CLOSED-CAPTIONS=NONE
video/720p/main.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=900000,RESOLUTION=640x360,CODECS="avc1.42c01e,mp4a.40.2",
  AUDIO="aac-main",SUBTITLES="subs",CLOSED-CAPTIONS=NONE
video/360p/main.m3u8

Читать сверху вниз: четыре аудиорендиции в группе aac-main, три рендиции субтитров в группе subs, три видеоварианта – каждый вариант ссылается на обе группы по их GROUP-ID. Зритель слышит одну аудиорендицию за раз и видит ноль или одну рендицию субтитров за раз; видеорендиция переключается по полосе через ABR. Атрибуты AUDIO= и SUBTITLES= на EXT-X-STREAM-INF – связка, говорящая «это видео можно совместить с любым элементом из этих групп». CLOSED-CAPTIONS=NONE – явный сигнал об отсутствии встроенных captions; задавать его явно лучше, чем опускать, потому что некоторые плееры трактуют отсутствие как «не знаю – попробуй извлечь» и зря жгут такты.

Каждый атрибут в каждой строке EXT-X-MEDIA имеет значение. LANGUAGE – это BCP 47 тег в кавычках – "en", "en-US", "fr", "pt-BR", "zh-Hans" – и плеер использует его, чтобы соотнести системную локаль при выборе дефолта. DEFAULT=YES помечает рендицию, которая играет, когда зритель не выразил предпочтения; только одна рендиция в группе может выставить этот флаг. AUTOSELECT=YES помечает рендицию как пригодную для system-driven выбора (Mac, настроенный на французский, выберет французское аудио, если оно AUTOSELECT=YES); рендиция, помеченная как DEFAULT, обязана быть и AUTOSELECT. FORCED=YES, только для субтитров, помечает forced-нарративный трек, который должен показываться независимо от пользовательского «субтитры включены». CHARACTERISTICS – список ролей доступности из таксономии iTunes media characteristics, разделённый запятыми: public.accessibility.describes-video для тифлокомментария, public.accessibility.transcribes-spoken-dialog для closed captions, public.accessibility.describes-music-and-sound для captions с описанием неречевых звуков. CHANNELS – количество и конфигурация аудиоканалов: "2" для стерео, "6" для 5.1, "12/JOC" для Dolby Digital Plus с Atmos Joint Object Coding-миксом, который downmix-ится в 5.1 на устройствах без Atmos.

Самый частый баг манифеста – рассогласованный GROUP-ID: строка EXT-X-STREAM-INF ссылается на AUDIO="aac-main", а аудиорендиции объявлены с GROUP-ID="aac-1". Плеер загружает вариант, не находит подходящую аудиогруппу и проигрывает видео молча. Проверяйте этот кейс в CI явно.

Второй частый баг – нет DEFAULT=YES в аудиогруппе. Спецификация HLS это допускает (плеер должен сам выбрать подходящую рендицию), но реальное поведение плееров отличается – некоторые модели Roku отказываются играть, некоторые берут трек по алфавиту независимо от системной локали. Всегда помечайте ровно одну рендицию в каждой группе как DEFAULT.

DASH: та же история, другие теги

DASH MPD выражает то же разделение через элементы AdaptationSet. Видео живёт в AdaptationSet с contentType="video"; каждый язык аудио – в своём AdaptationSet с contentType="audio" и lang="en"; каждый язык субтитров – в AdaptationSet с contentType="text" (или application для IMSC) и lang="fr". Плеер обходит MPD, выбирает по одному AdaptationSet из каждого contentType и комбинирует их.

DASH выражает доступность через дескрипторы Role, Accessibility и EssentialProperty. Трек тифлокомментария несёт <Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="1"/> (где «1» – код TVA AudioPurpose «для слабовидящих»), плюс <Role schemeIdUri="urn:mpeg:dash:role:2011" value="alternate"/> для пометки «не дефолт». Forced subtitle-трек несёт <Role schemeIdUri="urn:mpeg:dash:role:2011" value="forced-subtitle"/>. Closed-caption-трек (в отличие от обычных subtitles) несёт <Role value="caption"/>. Словарь более многословный, чем в HLS, и URI-неймспейсы труднее запомнить, но семантика та же.

CMAF подтягивает DASH и HLS к общему пакаджингу: CMAF требует, чтобы текстовые треки жили как сегментированные CMAF-треки – sidecar-WebVTT-файлы в строго CMAF-совместимом потоке не разрешены. На практике пакаджеры, целящиеся одновременно в DASH-IF и Apple-экосистему, выпускают WebVTT в двух формах: сырые .vtt для HLS-only-доставки и CMAF-обёрнутые WebVTT-сегменты (кодек wvtt) для DASH и строгого CMAF. MPD тогда перечисляет WebVTT AdaptationSet с mimeType="application/mp4" и codecs="wvtt". IMSC следует тому же паттерну с кодеком stpp.

Рис. 2. HLS выражает alt-audio и текст плоским списком EXT-X-MEDIA-рендиций, связанных с вариантами через GROUP-ID. DASH выражает то же дерево AdaptationSet'ов с дискриминацией по contentType и lang. Семантика идентична; различается только синтаксическая упаковка.

Аудио: один поток, много миксов

Слой аудио-рендиций несёт больше, чем просто альтернативные языки. Типичный премиум-стриминговый бандл отгружает, как минимум, такие аудиотреки на одно шоу:

ТрекЯзыкКаналыКодекПрименение
Оригинальный диалоговый миксen2.0AAC-LCДефолт для англоязычной аудитории
Оригинальный surrounden5.1AC-3 / E-AC-3Домашний кинотеатр (английский)
Atmos object-миксen12/JOCE-AC-3 + JOCAtmos-совместимые устройства
Локализованный дубляж (FR)fr2.0AAC-LCДефолт для франкоязычной аудитории
Локализованный дубляж (FR)fr5.1E-AC-3Французский домашний кинотеатр
Локализованный дубляж (ES, DE, JP, …)2.0AAC-LCПо одному на отгружаемый рынок
Тифлокомментарий (en)en2.0AAC-LCОбязательный a11y-трек
Режиссёрский комментарийen2.0AAC-LCБонусный контент

Плеер выбирает максимум один трек в каждый момент. Логика выбора, по убыванию приоритета: явный выбор пользователя из меню выигрывает; явная a11y-настройка (системный тумблер «Audio Descriptions» на iOS, «Audio Description» на Android TV) выигрывает дальше, против любой рендиции с CHARACTERISTICS="public.accessibility.describes-video" для языка пользователя; совпадение системной локали с LANGUAGE среди AUTOSELECT=YES выигрывает дальше; рендиция с DEFAULT=YES – последний резерв.

Значение channels мало, но критично. Современный телефон и Smart TV 2024 года оба понимают 5.1, но set-top box 2017 года может рендерить только стерео. Атрибут CHANNELS в спецификации HLS позволяет плееру пропустить рендиции, которые он не может отрисовать – 5.1-рендиция с CHANNELS="6" будет отфильтрована устройством stereo-only, и плеер откатится на 2.0 того же языка. Atmos сигнализируется суффиксом JOC: CHANNELS="12/JOC" для 5.1.4 или 7.1.4 Atmos-микса, CHANNELS="16/JOC" для 9.1.6. Устройства, не понимающие JOC, игнорируют рендицию; устройства, понимающие, извлекают объектные данные Dolby Atmos из payload Joint Object Coding параллельно с legacy 5.1-ядром.

Прагматичная лесенка 2026 года для tier-one OTT:

  • На язык: одна AAC-LC stereo-рендиция в 128 кбит/с для универсальной совместимости; одна E-AC-3 5.1 в 384 кбит/с для домашних кинотеатров; опционально одна Atmos-JOC в 768 кбит/с для Atmos-совместимого подмножества.
  • Плюс, на основной язык рынка: одна тифлокомментарий-AAC-LC stereo в 128 кбит/с с характеристикой describes-video.
  • Плюс, опционально: один режиссёрский комментарий AAC-LC stereo для контента, где это добавляет ценность.

Суммарный битрейт, добавляемый аудио, мал по сравнению с видео – при шести аудиорендициях по 200–800 кбит/с это, может быть, 2 Мбит/с дополнительной полосы даже до того, как плеер выбрал одну, а доставляется только одна. Стоимость – это усилие на кодирование, сложность пакаджинга и дисциплина каталога, чтобы не забыть, что шоу 9847 серия 12 нуждается в Atmos-рендере на английском и стерео-дубляже на семи языках.

Доступность: теги, которые решают, дойдут ли captions до своей аудитории

Просто наличия captions недостаточно. WebVTT-трек, перечисленный в манифесте без правильных characteristics, появится в меню плеера как «English», а не как «English CC», и зритель, у которого включён системный тумблер «Always show captions», не получит их автоматически. Спецификация HLS заимствует у Apple iTunes Connect словарь media-characteristics для атрибута CHARACTERISTICS, и проставление правильных значений – это и есть то, что превращает generic-subtitle-трек в распознанный closed-caption или audio-description-трек на уровне платформы.

Релевантные characteristics:

  • public.accessibility.transcribes-spoken-dialog – captions включают письменную форму устного диалога. Отличает CC и subtitles от только-переводных subtitles.
  • public.accessibility.describes-music-and-sound – captions также описывают неречевые звуки ([хлопает дверь], [зловещая музыка]). В паре с transcribes-spoken-dialog это канонический сигнал, что трек – это CC для глухих и слабослышащих.
  • public.accessibility.describes-video – аудиорендиция является тифлокомментарием для слабовидящих, с диктором, описывающим визуальное действие между репликами.
  • public.easy-to-read – captions упрощены для когнитивной доступности, с короткими предложениями и более медленной скоростью чтения (новое требование, поднимаемое из ЕС).

DASH выражает эквивалент через дескрипторы Accessibility, как описано выше. Юридические мандаты FCC, EAA, U.K. Equality Act и платформенные политики app store – все опираются на то, что плеер корректно поднимает треки с этими тегами, а не просто на наличие треков.

Типичная ошибка – пометить переводной subtitle-трек как closed-caption. Французский subtitle-трек, переводящий английский диалог для франкоязычной слышащей аудитории, не должен нести describes-music-and-sound, потому что он его не описывает. Сделав это, вы говорите платформе, что трек – это CC, и зрители, ищущие a11y-контент, будут введены в заблуждение. Резервируйте CC-characteristics для треков, которые действительно описывают неречевые звуки; переводные subtitles помечайте как plain без этих флагов.

Вторая типичная ошибка – забыть про FORCED=YES-трек. Если в оригинальной нарезке фильма француз говорит на французском в сцене, предназначенной для англоязычной аудитории, английская версия нуждается в forced-subtitle-треке, который покажет только эти французские реплики, независимо от того, включил ли зритель субтитры. Паттерн HLS – отдельная рендиция EXT-X-MEDIA с FORCED=YES, содержащая только эти cues, в паре с обычной английской subtitle-рендицией для тех, кому нужны полные captions. Без forced-трека аудитория услышит французский и не увидит перевода.

Продакшен-пайплайн: от сценария до манифеста

Трек captions не появляется сам. Продакшен-пайплайн, кладущий французский дубляж или CC-трек в манифест, включает несколько передач, и когда одна из них молча падает, баг остаётся инженерной команде расследовать неделями позже. Упрощённый пайплайн:

  1. Сценарий и dialogue list финализируется продакшен-командой – исчерпывающий список каждой устной реплики с таймкодами, привязанными к мастер-таймлайну.
  2. Студия captions транскрибирует оригинальный диалог плюс неречевые звуки, выпуская исходный файл SCC, MCC или IMSC, выровненный по мастер-таймкоду.
  3. Команда перевода субтитров переводит dialogue list на каждый отгружаемый язык, выпуская файлы SRT или WebVTT на язык, выровненные по тому же таймкоду.
  4. Студия дубляжа записывает дубляж на каждом языке против мастер-картинки, выпуская один аудиостем на язык.
  5. Студия тифлокомментария пишет и записывает описательную закадровую речь между репликами, выпуская стем тифлокомментария на каждый основной язык рынка.
  6. Mastering и QC проверяют, что каждый файл captions воспроизводится чисто против мастер-картинки и каждый аудиостем синхронен с картинкой с правильным офсетом.
  7. Энкодер производит видеорендиции; пакаджер оборачивает аудиостемы и файлы captions в сегментированные потоки; манифест ссылается на каждое как на рендицию с правильными LANGUAGE, CHARACTERISTICS, DEFAULT, AUTOSELECT, FORCED и CHANNELS.
  8. CDN кеширует всё это, и плеер выбирает правильные треки для каждого зрителя.

Где это ломается: шаг 7 – место, где вводится большинство a11y-багов. Энкодер и пакаджер агностичны к контенту – они видят аудиофайл A и файл captions B и производят потоки, не зная, что A – это тифлокомментарий, а B – forced-subtitle-трек. Либо upstream-пайплайн несёт эти метаданные (XML-сайдкар, описывающий роль и язык каждого файла), и пакаджер их соблюдает, либо пакаджер крутит статическую конфигурацию, которую надо обновлять под каждое шоу.

В OTT-проектах Фора Софт самым надёжным паттерном оказывается CMS-driven сборка манифеста: каталог CMS хранит каждый аудио- и caption-ассет с языком, ролью, конфигурацией каналов и a11y-флагами как поля первого класса, а шаг сборки в пакаджере читает эти поля, чтобы произвести правильные объявления EXT-X-MEDIA или AdaptationSet. Статические шаблоны манифеста не масштабируются дальше горстки шоу.

Рис. 3. Восемь шагов от сценария до доставки. Большинство a11y-багов вводится на шаге 7 – в пакаджере – когда метаданные CMS о языке, роли, конфигурации каналов или a11y-флагах отсутствуют или неверны.

Что плеер реально делает

Когда плеер загружает манифест, он парсит каждую строку EXT-X-MEDIA и EXT-X-STREAM-INF в in-memory модель: множество вариантов, каждый указывающий на одну или несколько групп рендиций. Начальный выбор работает примерно так:

  1. Найти системную локаль (например, fr-CA).
  2. Для каждого типа рендиции (audio, subtitles, closed-captions) отфильтровать до рендиций с AUTOSELECT=YES.
  3. Внутри – предпочесть рендицию, чей LANGUAGE лучше соответствует локали. Соответствие BCP 47 нежёсткое: fr-CA сначала точно совпадает с fr-CA, затем с fr на уровне языка, затем по дефолтам.
  4. Применить a11y-overrides: если системный «Audio Descriptions» включён, предпочесть аудиорендиции с CHARACTERISTICS=public.accessibility.describes-video для совпавшего языка. Если «Captions and Subtitles» включён, включить лучшую CC-рендицию.
  5. Если ничего не подходит – откатиться на DEFAULT=YES в каждой группе.
  6. Применить forced-subtitle-рендицию (FORCED=YES), которая соответствует выбранному языку аудио – это кейс, когда зритель, не включавший subtitles, всё равно видит forced-трек для иноязычных надписей.

Затем плеер начинает параллельную загрузку сегментов выбранного варианта, выбранной аудиорендиции и нуля или одной subtitle-рендиции. Каждый трек тянется с отдельного URL, декодируется отдельным пайплайном и синхронизируется через media presentation timestamp.

Типичная ошибка – полагаться, что плеер сам разберётся. Плееры следуют спецификации, но в спецификации есть неоднозначности. Манифест с двумя AUTOSELECT=YES французскими аудиорендициями и без DEFAULT=YES будет резолвиться по-разному в iOS, Android Exoplayer, hls.js и Shaka. Всегда объявляйте ровно одну DEFAULT=YES на группу, даже если это кажется избыточным.

Типичная ошибка – расхождение LANGUAGE. WebVTT-трек с LANGUAGE="en" не будет автовыбран для зрителя с системной локалью en-GB, если плеер не реализует BCP 47-fallback к базовому языку. Большинство реализует, но не все. Безопасный паттерн – помечать треки максимально специфичным BCP 47-тегом, который реально описывает контент (en-US, pt-BR, zh-Hant-HK), и предоставлять базовую рендицию (en, pt, zh) как fallback для несовпавших локалей.

Где в это вписывается Фора Софт

Фора Софт строит стриминговые системы с 2005 года в OTT, телемедицине, e-learning, видеонаблюдении и живых конференциях. Captions и мультиязычное аудио появляются в каждой категории, с которой мы работаем: e-learning-платформе, доставляющей курсы по Европе, нужны forced narrative subtitles на семи языках; телемедицинскому развёртыванию на рынке со стареющим населением нужны CC на каждой консультации; OTT-продукту, запускающемуся в Квебеке, нужно квебекское-французское аудио с квебекскими-французскими субтитрами, отличными от европейских. Мы проектируем схему каталога, шаг пакаджинга, сборку манифеста и UI плеера вместе – потому что баг всегда на одной из передач, а не в каком-то одном изолированном шаге.

Типичные грабли, найденные через две недели после запуска

  • Французское аудио играет, когда системный язык на iOS – французский, а французские субтитры – нет – причина: subtitle-рендиция помечена AUTOSELECT=NO, скопированная из шаблона forced-subtitle.
  • 5.1-рендиция выбирается на stereo-Roku и downmix-ится в тихое некачественное стерео – причина: атрибут CHANNELS отсутствует, плеер не может отфильтровать рендицию.
  • CC-трек появляется в меню iOS как «English» вместо «English CC» – причина: атрибут CHARACTERISTICS без пары transcribes-spoken-dialog,describes-music-and-sound.
  • WebVTT-cues появляются не вовремя после первого refresh манифеста на live – причина: пакаджер забыл выдать X-TIMESTAMP-MAP на пер-сегментных WebVTT-файлах.
  • Испанский дубляж играет в Мексике, но не в Аргентине – причина: есть треки LANGUAGE="es-MX" и LANGUAGE="es-AR", но нет fallback-рендиции LANGUAGE="es", и плеер отказался откатываться.
  • hls.js нормально играет WebVTT на Chrome, но показывает пустые captions в Safari – причина: UTF-8 BOM в начале файла сбивает парсер WebKit. Стрипайте BOM на пакаджере.
  • Dolby Atmos играет как тишина на Roku Express 2018 года – причина: только рендиция 12/JOC объявлена в группе, устройство не умеет декодировать JOC; отгружайте и 6 (5.1) fallback в той же группе.

Эталонные манифесты

PDF-компаньон к этой статье упаковывает два end-to-end-эталонных манифеста – один HLS, один DASH – для гипотетического трёхъязычного шоу с тифлокомментарием и мультибитрейтом, с каждым атрибутом задокументированным. Используйте как канонический старт для следующего шоу в каталоге.

Скачать справочный пак по captions и мультиаудио

Ключевые выводы

  • Captions и аудио – независимые группы рендиций в манифесте, сшиваются с видео в плеере через GROUP-ID (HLS) или выбор AdaptationSet (DASH).
  • WebVTT – универсальный текстовый формат; IMSC1 – broadcast-уровень внутри fMP4; CEA-608/708 выживает как in-bitstream legacy.
  • LANGUAGE (BCP 47), DEFAULT, AUTOSELECT, FORCED, CHANNELS и CHARACTERISTICS – шесть атрибутов, решающих, дойдёт ли нужный трек до нужного зрителя.
  • Atmos сигнализируется CHANNELS="12/JOC" или "16/JOC"; всегда парьте с 5.1 или stereo fallback для устройств без JOC.
  • Доступность – это дисциплина тегов, а не просто наличие треков: transcribes-spoken-dialog, describes-music-and-sound, describes-video – то, что читают платформы.
  • CMS-driven сборка манифеста масштабируется дальше горстки шоу; статические шаблоны – нет.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.