Legan Studio
Все статьи
~ 3 мин чтения

Видео-стриминг на сайте: HLS, DASH, MUX

Как доставить видео в браузер: HLS vs DASH, адаптивный битрейт, российские CDN, защита контента, плееры hls.js и shaka, серверы и стоимость.

  • веб
  • интеграции
  • разработка

«Залейте видео в <video> и всё будет работать» — так делают на лендинге с одним 5-секундным роликом. Если у вас полнометражные видео, обучающие курсы, прямые трансляции или платный контент — нужен полноценный стриминг с адаптивным битрейтом, нормальным CDN и плеером, который не уронит браузер. Разбираем.

Простой <video> — когда хватает

<video src="/video/hero.mp4" autoplay muted playsinline loop poster="/video/hero.jpg" />

Подходит, если:

  • Видео < 30 секунд и < 5 МБ.
  • Один файл одного качества.
  • Не платный контент.
  • Аудитория с быстрым интернетом.

Для всего остального — стриминг.

HLS vs DASH

Два основных протокола адаптивного стриминга. Видео нарезается на короткие сегменты (по 2-10 сек) разного качества, плеер выбирает подходящее по скорости сети.

КритерийHLSDASH
Кто разработчикAppleMPEG / международный стандарт
Манифест.m3u8.mpd
Контейнер сегментаTS / fMP4fMP4
Поддержка Safariнативночерез MSE
Поддержка Chromeчерез hls.jsнативно или через shaka
Стандарт в РФHLS (90% случаев)реже
DRMFairPlayWidevine / PlayReady

Прагматично — выбирайте HLS. Один формат покрывает всё, в т.ч. iPhone (где DASH без MSE не работает).

Создание HLS из исходника

ffmpeg — стандарт:

ffmpeg -i source.mp4 \
  -filter_complex \
  "[0:v]split=3[v1][v2][v3]; \
   [v1]scale=w=1920:h=1080[v1out]; \
   [v2]scale=w=1280:h=720[v2out]; \
   [v3]scale=w=854:h=480[v3out]" \
  -map [v1out] -c:v:0 libx264 -b:v:0 5000k \
  -map [v2out] -c:v:1 libx264 -b:v:1 2800k \
  -map [v3out] -c:v:2 libx264 -b:v:2 1400k \
  -map a:0 -map a:0 -map a:0 \
  -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
  -f hls -hls_time 6 -hls_playlist_type vod \
  -master_pl_name master.m3u8 \
  output_%v/playlist.m3u8

На выходе: master.m3u8 (выбор качества) + папки с сегментами для каждого качества. Загружаете в S3-совместимое хранилище, раздаёте через CDN.

Готовые сервисы

СервисОсобенностьЦена
MUXтоповое API, аналитика, оплата проблематична$0.005/мин encoding
Cloudflare Streamдёшево, простое API$5/1000 мин хранения
Bunny Streamдёшево, российский трафик ОК$1/1000 мин
VK Видео APIроссийский, но ограниченный APIбесплатно с ограничениями
Yandex Video Cloudроссийский, под новостные / VODконтракт
Kinescopeроссийский, конкурент Vimeoот 2 000 ₽/мес
Свой стек (ffmpeg + S3 + CDN)контроль, нужна командастоимость инфры

Для российского проекта 2026 — Kinescope или свой стек на Yandex/Selectel CDN. MUX и Cloudflare — отлично, но с оплатой сложно.

Плееры

ПлеерТехнологияКогда
video.jsуниверсальный, плагиныстандарт по умолчанию
hls.jsHLS на всех браузерахесли нужен только HLS
Shaka PlayerDASH + HLS, Googleсложные сценарии
Plyrминималистичный UIлендинги, простые случаи
MUX Playerесли используете MUXbrand consistency
"use client";
import Hls from "hls.js";
import { useEffect, useRef } from "react";

export function HlsVideo({ src, poster }) {
  const ref = useRef<HTMLVideoElement>(null);

  useEffect(() => {
    const video = ref.current!;
    if (video.canPlayType("application/vnd.apple.mpegurl")) {
      video.src = src;
    } else if (Hls.isSupported()) {
      const hls = new Hls();
      hls.loadSource(src);
      hls.attachMedia(video);
      return () => hls.destroy();
    }
  }, [src]);

  return <video ref={ref} controls poster={poster} playsInline />;
}

Safari читает HLS нативно, для остальных — hls.js.

Адаптивный битрейт

Плеер сам выбирает качество исходя из пропускной способности и буфера. Главное — иметь несколько качеств в манифесте (минимум 3: 480p, 720p, 1080p).

В UI:

  • Auto (по умолчанию) — плеер сам решает.
  • Ручной выбор — пользователь может зафиксировать.
  • Индикатор текущего качества — особенно для платного контента.

Защита контента

«Чтобы не скачивали» — частый запрос. Реальность:

  • Запретить полностью — нельзя. Любое видео, которое можно посмотреть, можно записать (хотя бы экран).
  • Усложнить — да. DRM (Widevine, FairPlay, PlayReady), signed URLs с TTL, токены доступа на сегменты.
  • Watermarking — разный сегмент для разных пользователей, можно отследить, кто слил.

Простая защита (для базы):

// signed URL на манифест
const token = jwt.sign({ video: id, exp: Date.now() / 1000 + 3600 }, SECRET);
const url = `https://cdn.example.ru/videos/${id}/master.m3u8?token=${token}`;

CDN проверяет токен — если истёк или подделан, 403. Для пиратов это не препятствие, но 95% «случайных скачиваний» отсекает.

Live-стриминг

Прямой эфир — отдельная история. Вебинары, события, спортивные трансляции.

Стек:

  1. Источник (камера, OBS) шлёт RTMP на ingress-сервер.
  2. Сервер (nginx-rtmp, Restreamer, MediaMTX) пакует в HLS/LL-HLS.
  3. CDN раздаёт сегменты.
  4. Плеер показывает.

Задержка: классический HLS — 20-30 секунд (3 сегмента по 6-10 сек). LL-HLS — 2-5 секунд. WebRTC — < 1 секунды (но сложно масштабировать на 10к+ зрителей).

Аналитика

Что мерять:

  • Старт воспроизведения (% пользователей, начавших).
  • Удержание (минута за минутой, где пользователи уходят).
  • Переключения качества (если много — сеть слабая или плеер плохо подобран).
  • Buffering events (плохой пользовательский опыт).
  • Среднее время просмотра.

MUX Data — стандарт, но платный. Свой подход — посылать события на свой бэкенд + Plausible/PostHog.

Стоимость инфраструктуры

Пример: 1000 уникальных просмотров в день среднего видео (10 минут, 720p, 2 Мбит/с):

  • Трафик: 1000 × 10 мин × 60 сек × 2 Мбит/с / 8 = 150 ГБ/день, 4.5 ТБ/мес.
  • Yandex CDN: ~₽3-7/ГБ → 14-30 тыс. ₽/мес.
  • Bunny CDN: ~$0.005/ГБ → ~$22/мес.
  • Свой VPS как origin (S3 + CDN кеш) — ещё пара тыс. ₽.

Для маленького проекта подъёмно. Для миллионов просмотров — нужно тщательно считать.

Контент в РФ и юрисдикция

Размещение видео с пользовательским контентом подпадает под Закон об ОРИ (организаторах распространения информации). Для маленьких проектов с собственным контентом — обычно вне зоны риска. Для UGC-платформ — отдельная юридическая работа.

Также: видео для российской аудитории с зарубежного CDN — может быть медленно или временами недоступно. Используйте российский CDN как primary.

Итого

Для лендинга — <video> с MP4. Для блога с обучающими роликами — Kinescope или Bunny Stream, минимум возни. Для платформы с тысячами часов видео — свой стек на ffmpeg + S3 + CDN с продуманной защитой и аналитикой. Главное — заранее посчитать трафик, иначе CDN-счёт может приехать неожиданным сюрпризом.

Частые вопросы

HLS или MP4 для лендинга?

MP4, если ролик короткий (до 30 сек) и одного качества. HLS — когда нужна адаптивность к сети, длительные видео, защита контента. На лендинге обычно автозапускающееся видео в hero — это MP4 с muted+playsinline, 5 МБ максимум, иначе мобильные пользователи будут проклинать.

Сколько стоит загрузить и хранить видео?

Зависит от объёма. Для 100 видео по 10 мин в 1080p — ~50-100 ГБ хранения, S3-совместимый Yandex Object Storage от 1.5 ₽/ГБ/мес = 75-150 ₽/мес за хранение. Энкодинг — единоразово, тратит CPU (час 1080p в HLS на быстром сервере — 5-15 минут). Самые большие расходы — трафик отдачи, не хранение.

Можно ли защитить видео от скачивания полностью?

Нет. Любое видео, которое отображается, можно записать с экрана. Можно усложнить: DRM (Widevine + FairPlay) блокирует браузерное скачивание и простую запись через расширения. Watermarking позволит отследить, кто слил. Но 100% защита невозможна, и не стоит тратить на неё месяцы — лучше инвестируйте в качество контента.

Kinescope или свой стек?

Kinescope — если у вас 5-50 видео и не хочется заниматься энкодингом, CDN, аналитикой. От 2-5 тыс. ₽/мес, всё работает из коробки. Свой стек — если 1000+ видео, нужен полный контроль и кастомная защита. Точка перехода — обычно ~10-20 тыс. ₽/мес расходов на Kinescope, тогда self-hosted уже выгоден.

LL-HLS или WebRTC для прямого эфира?

Зависит от задачи. LL-HLS (2-5 сек задержки) — для трансляций один-к-многим (вебинары, спорт): легко масштабируется через CDN, сотни тысяч зрителей. WebRTC (< 1 сек) — для интерактивных форматов (онлайн-аукционы, обучение с диалогом): сложнее масштабировать, нужен SFU. Для большинства бизнес-вебинаров достаточно LL-HLS.

Как сделать subtitle и многоязычные дорожки?

HLS поддерживает: WebVTT для субтитров, отдельные альтернативные аудио-дорожки. В манифесте — #EXT-X-MEDIA:TYPE=SUBTITLES,... и TYPE=AUDIO,.... Плееры (hls.js, video.js) автоматически дают переключатель в UI. Для простого случая (один язык субтитров) хватает обычного <track src="ru.vtt" kind="subtitles"> в video теге.

Какое разрешение и битрейт оптимально?

Стандартный набор: 480p @ 1.4 Mbps, 720p @ 2.8 Mbps, 1080p @ 5 Mbps. Если контент критичен по качеству (фильмы) — добавьте 1440p @ 8 Mbps. Для лекций и говорящих голов хватает 720p, 1080p редко нужно. Кодек H.264 — универсально, H.265/HEVC — на 30-50% меньше при том же качестве, но не везде поддерживается без аппаратной декодировки.