Перейти к основному содержимому

Хранение видео в Yandex.Cloud

· 12 мин. чтения

Если вам нужно добавить на свой сайт видео, то может возникунуть вопрос где его хостить и как потом раздавать. В этом посте я постараюсь разобрать варианты и дать примеры использования Yandex.Cloud Object Storage.

Формат файла mp4 знаком наверное всем. Но стоит если мы хотим показывать видео на сайте эффективно стоит задуматься лучшее ли это решение для нашей задачи — просто выложить все видео одним mp4-файлом?

HLS

Протокол HLS (HTTP Live Streaming) был предложен в 2009 и к настоящему времени стал стандартом де факто в области адаптивного видео стриминга.

HLS был разработан Apple, как замена их собственной разработки Quicktime Streaming Server, а также как альтернатива другому популярному на тот момент протоколу Real-Time Messaging Protocol (RTMP). RTMP, выпущенный Adobe в 2002 году, использовал технологию Flash, чтобы передавать видео с низкой задержкой через интернет. Не смотря на то, что Flash мертв, RTMP до сих пор популярный протокол для видеотрансляций.

Что же такое HLS?

Хотя HLS может быть не на слуху, но вместе с MPEG-DASH и SRT, он один из главных протоколов обеспечивающих доставку видео и аудио контента в современном интернете. Велики шансы, что вы пользуетесь им каждый день, даже не задумываясь об этом. Особенно если вы пользователь экосистемы Apple.

Хотя HLS и был разработан в Apple он широко поддерживается и на других платформах: смартфонах Android и Apple, Linux, Microsoft, OTT устройствах, smart TV, а так же в браузерах Google Chrome, iOS Safari, Safari, Android Browser, Microsoft Edge, Chrome for Android и Opera Mobile. На части платформ поддержка нативная, в других же она реализована через js-плееры.

Тот факт, что потоковая передача HLS обычно осуществляется через видеоплеер HTML5, делает его универсальным и широко совместимым. HLS часто называют HTML5-видео, что не совсем точно. Видеоплеер HTML5 просто совместим с HLS.

Что значит протокол?

HLS — это протокол потоковой передачи видео. Но что именно это означает? Возможно, вы слышали термин “кодек”, но важно отметить, что потоковый протокол — это не кодек. Протокол — это более широкая категория. Потоковый протокол — это стандартизированный метод передачи видеоконтента между устройствами. Протокол может предполагать использование определенного кодека (или кодеков), который будет использоваться для сжатия и распаковки видео- и аудиоконтента. Например, HLS поддерживает множество популярных кодеков:

  • Audio: AAC-LC, HE-AAC+ v1 & v2, xHE-AAC, Apple Lossless, FLAC
  • Video: H.265, H.264

Преимущества HLS

HLS предназначен для обеспечения надежности и динамической адаптации к сетевым условиям путем оптимизации (т. е. ухудшения или улучшения) воспроизведения видео для доступных скоростей Интернета. Но кроме того, он также заботится о многих вещах, связанных с доставкой видеоконтента зрителям:

  • Стриминг с адаптивным битрейтом (Adaptive Bitrate Streaming) — HLS подстраивает качество видео под текущую скорость интернет канала. Это позволяет авторам предлагать несколько видеопотоков в разном качестве, а плееру переключаться между ними незаметно.

Пример среднего битрейта видео (kbit/s). Источник: Apple

  • **Совместимость со многими устройствами **— HLS гарантирует, что ваше видео контент сможет быть проигран на любом устройстве, которое может запустить совместимый плеер (например HTML5)
  • Субтитры — HLS поддерживает скрытые субтитры. Это позволяет авторам встроить несколько потоков субтитров, например на разных языках.
  • Возможность менять аудио дорожку — HLS также поддерживает несколько потоков аудио между которыми можно переключаться.
  • Возможность вставлять рекламу с помощью технологий VPAID и VAST.
  • Масштабирование — HLS обладает высокой масштабируемостью для доставки видеофайлов и потокового контента через глобальные сети доставки контента (CDN). В отличие от протокола RTMP, используемого совместно с Flash player, HLS может легко масштабироваться для доставки с помощью обычных веб-серверов через глобальную сеть доставки контента (CDN). Распределяя рабочую нагрузку по сети серверов, CDN приспосабливаются к всплескам вирусной аудитории и большим, чем ожидалось, живым аудиториям. CDN также помогают улучшить качество просмотра, кэшируя аудио-и видеосегменты. Для сравнения, поддержка CDN для RTMP быстро снижается. RTMP также требует использования выделенного сервера потоковой передачи, что делает его более ресурсоемким для развертывания.
  • Защита от пиратства через поддержку большого числа DRM технологий.

Вот более подробный пост про то как можно ограничить доступ к видео при помощи AES-128 шифрования.

Недостатки HLS

HLS имеет некоторые ограничения, но они по своей сути связаны с конкретными проектными решениями, принятыми при разработке протокола.

Часть этих ограничений связана с задержкой. Поскольку HLS ставит во главу угла комфорт пользователя, а не низкую задержку, live-контент, транслируемый с использованием протокола HLS, не является достаточно “живым”. Зритель увидит его с задержкой до 30 секунд. Таким образом, HLS не является лучшим выбором для таких приложений, как веб-конференции или управление устройствами, где необходима видео в реальном времени (камеры и дроны). В этом случае лучше использовать более быстрый потоковый протокол, например WebRTC (Web Real-Time Communications).

Задержка в HLS возникает из-за того, что протокол разбивает видео на множество многосекундных фрагментов (или сегментов), которые обычно имеют длину 2–6 секунд. И поскольку протокол HLS также должен буферизировать несколько таких небольших сегментов одновременно, задержка может составлять десятки секунд. Однако если задержка или плохие сетевые условия не являются проблемой, то HLS-это протокол, который вам нужен.

Итак почему стоит использовать именно HLS?

  • С HLS создатели контента могут подготовить версии своего видео для нескольких разных интернет-каналов и условий воспроизведения (3G, 4G, LTE, медленный публичный Wi-Fi, быстрый домашний интернет).
  • Различные поставщики CDN, постепенно отказываются от поддержки RTMP, заявляя, что его развертывание становится слишком дорогим. Вместо этого набирают популярность такие протоколы, как HLS, а также SRT и MPEG-DASH.
  • Поскольку Adobe перестал поддерживать технологию, на которую опирается RTMP, это только вопрос времени, когда ваш процесс потоковой передачи RTMP станет технологически устаревшим без поддержки со стороны компании, которая его создала.
  • HLS оптимизирует доставку аудио и видео на самый широкий спектр мобильных, настольных, планшетных и OTT-устройств.
  • HLS позволяет доставлять видео по запросу с помощью шифрования и аутентификации.
  • HLS значительно снижает затраты на CDN, обеспечивая только оптимальный битрейт для клиентской сети и избегая сценария “частичного воспроизведения и полной загрузки”, присущего прогрессивной потоковой передаче http, например, когда все видео представлено одним mp4-файлом.
  • Apple App Store требует, чтобы приложения с более чем 10-минутным видео использовали HLS.

Практическая часть

Надеюсь я смог вас убедить, что сегодня для распространения видео контента через интернет стоит смотреть в стону HLS.

Давайте теперь рассмотрим пример как нам для этого использовать объектное хранилище в Яндекс Облаке.

Object Storage — это решение для хранения больших объемов данных за относительно небольшие деньги, идеально подходящее для чего-то вроде видеофайлов, которые, как правило, довольно большие. Доступ к файлам (или объектам, как их часто называют) осуществляется через HTTP(S), что делает его отличным решением для хранения (и обслуживания) ваших HLS видео.

Для начала нам понадобится бакет в хранилище. Если у вас его нет, то вот инструкция как его создать.

Подготовка видео

Если у вас уже есть видео в формате HLS, то смело проматывайте до следующего параграфа.

Если же его нет, то нам понадобится утилита ffmpeg при помощи которой вы можете конвертировать видео и аудио во множество форматов, в том числе и HLS.

Установка ffmpeg

Windows

  • Скачайте последнюю версию отсюда
  • Разархивируйте
  • Откройте консоль в папке
  • Выполните ./ffmpeg — вы должны будете увидеть информацию о версии ffmpeg.

Mac OS X

  • Установите homebrew
  • Выполните brew install ffmpeg
  • Затем вызовите ffmpeg — вы должны будете увидеть информацию о версии ffmpeg

Ubuntu

sudo add-apt-repository ppa:mc3man/trusty-media
sudo apt-get update
sudo apt-get install -y ffmpeg

CentOS / Fedora

yum install -y ffmpeg

Видео для примера

Возьмем какой-нибудь видео-файл и посмотрим информацию о нем:

ffprobe -hide_banner sample.mkv

Вы увидите что-то типа такого вывода в консоли

Input #0, matroska,webm, from 'sample.mkv':
Metadata:
title : Big Buck Bunny
encoder : libebml v0.7.8 + libmatroska v0.8.1
creation_time : 2008-11-17T23:28:21.000000Z
Duration: 00:09:56.48, start: 0.000000, bitrate: 9733 kb/s
Stream #0:0: Video: h264 (Main), yuv420p(tv, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, 24 fps, 24 tbr, 1k tbn, 2k tbc (default)
Metadata:
title : Big Buck Bunny
Stream #0:1: Audio: ac3, 48000 Hz, 5.1(side), fltp, 448 kb/s (default)
Metadata:
title : AC3 5.1 448kbps
Stream #0:2: Subtitle: subrip (default)
Metadata:
title : Intro

Конвертация

Подготовим команду для конвертации видео.

export filename=sample
mkdir $filename
ffmpeg -i $filename.mkv -vf \ scale=w=1280:h=720:force_original_aspect_ratio=decrease \
-map 0:v:0 -map 0:a:0 \
-c:a:0 -ar 48000 \
-c:v h264 -profile:v main -crf 20 -sc_threshold 0 \
-g 48 -keyint_min 48 -hls_time 4 \
-hls_playlist_type vod \
-b:v 2800k -maxrate 2996k -bufsize 4200k
-b:a 128k \
-hls_segment_filename $filename/720p_%03d.ts $filename/720p.m3u8

Теперь подробно разберем что значат все эти ключи:

  • -i sample.mp4— задает sample.mp4 в качестве входного файла
  • -vf "scale=w=1280:h=720:force_original_aspect_ratio=decrease" — смасштабировать видео до максимальных размеров в пределах заданных размеров 1280x720 с сохранением соотношения сторон
  • -c:a:0 aac -ar 48000 -ac:a:0 2 -b:a:0 128k — задаем аудиокодек AAC с частотой дискретизации 48кГц и битрейтом 128k. -ac:a:0 2 указывает, что если в первом аудиопотоке (a:0) каналов более чем 2 смиксовать их в стереосигнал.
  • -c:v h264 — устанавливаем видеокодек H264, являющийся стандартным кодеком для HLS. Этот кодек без аппаратного ускорения. Если вы будете подготавливать на Mac Os X, то вы можете попробовать использовать значение h264_videotoolbox. Для других платформ так же есть кодеки с поддержкой аппаратного ускорения.
  • -profile:v main — устанавливаем профиль кодека H264 в main — это значит включить поддержку всех современных устройств. Подробнее
  • -crf 20 - Constant Rate Factor — высокоуровневая настройка качества
  • -g 48 -keyint_min 48 — ВАЖНО создавать ключевой кадр (I-frame) каждые 48 кадров (~2 сек) — влияет на корректную нарезку на сегменты
  • -sc_threshold 0 — не создавать ключевые кадры при смене сцены
  • -b:v:0 2500k -maxrate 2675k -bufsize 3750k — ограничить битрейт видео. Конкретные значения стоит подбирать исходя из вашего видео. Подробнее в параграфе «Как правильно выбрать битрейт»
  • -hls_time 4 — длина сегмента в секундах. Реальная длина будет зависить от ключевых кадров
  • -hls_playlist_type vod — добавляет #EXT-X-PLAYLIST-TYPE:VOD тэг и сохраняет все сегменты в плейлист
  • -hls_segment_filename sample/720p_%03d.ts — явным образом задать имена файлов для сегментов
  • sample/720p.m3u8 — путь до плейлиста, также говорим ffmpeg выводить его в формате HLS (.m3u8)

Эта команда сгенерирует HLS плейлист и сегменты и сложит их в папку sample.

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

Мы создадим 4 версии с разрешениями:

  • 1080p 1920x1080 (original)
  • 720p 1280x720
  • 480p 842x480
  • 360p 640x360
export filename=sample
mkdir $filename
ffmpeg -hide_banner -y -i $filename.mkv \
-vf scale=w=640:h=360:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -ac 2 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 800k -maxrate 856k -bufsize 1200k -b:a 96k -hls_segment_filename $filename/360p_%03d.ts $filename/360p.m3u8 \
-vf scale=w=842:h=480:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -ac 2 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 1400k -maxrate 1498k -bufsize 2100k -b:a 128k -hls_segment_filename $filename/480p_%03d.ts $filename/480p.m3u8 \
-vf scale=w=1280:h=720:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -ac 2 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 2800k -maxrate 2996k -bufsize 4200k -b:a 128k -hls_segment_filename $filename/720p_%03d.ts $filename/720p.m3u8 \
-vf scale=w=1920:h=1080:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -ac 2 -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 5000k -maxrate 5350k -bufsize 7500k -b:a 192k -hls_segment_filename $filename/1080p_%03d.ts $filename/1080p.m3u8

Мастер плейлист

HLS-плеер должен знать, что существует несколько версий нашего видео, поэтому мы создаем мастер-плейлист HLS, чтобы указать их и сохранить вместе с другими плейлистами и сегментами в файл playlist.m3u8

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
360p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480
480p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p.m3u8

Как правильно выбрать битрейт

Битрейт зависит в основном от разрешения и типа контента. При установке слишком низкого битрейта пикселизация изображения будет происходить особенно в тех областях, где происходит быстрое движение, когда битрейт слишком высок, выходные файлы могут быть чрезмерно большими без дополнительного значения.

Чтобы выбрать правильный битрейт, нужно понимать его содержимое. Видео с резкими движениями, например спортивные или новостные события, потребует более высокого битрейта, чтобы избежать пикселизации, в то время как для контента с плавными движениями в кадре, например, музыкальные концерты или интервью, будет достаточно низкого битрейта без видимых изменений качества.

Вот некоторые хорошие значения по умолчанию для начала:

Загрузка данных

Убедитесь, что тип контента списка воспроизведения и сегментов видео (.ts) установлен в application/x-mpegURL и video/MP2T соответственно. Если вы загружаете файлы при помощи s3cmd, то он проставит корректные заголовок Content-type будет установлен корректно.

Настройка бакета

Для того чтобы видеоплееры могли корректно получить доступ к видео файлам небходимо указать CORS-настройки в бакете.

Это максимально широкое правило для примера.

Все готово.

Если вы хотите ограничить, на какие сайты можно будет встраивать видео, то прочитайте этот пост.

Теперь можно выкладывать видео на свой сайт.

import React, { useRef, useState } from "react"

import Layout from "../components/layout"
import ReactPlayer from "react-player"
import * as Hls from "hls.js"

const DemoPage = () => {
const player = useRef(null)
const [levels, setLevels] = useState([])

const handleReady = (player) => {
const hls = player.getInternalPlayer("hls") as Hls
setLevels(hls.levels)
}

const handleLevelClick = (level) => () => {
player.current.getInternalPlayer("hls").currentLevel = level
}

return (
<Layout>
<div style={{ maxWidth: "720px", marginBottom: "1.45rem" }}>
<ReactPlayer
ref={player}
onReady={handleReady}
className="react-player"
url="https://expample.com/sample/playlist.m3u8"
width="100%"
height="100%"
controls={true}
/>
</div>
<div>
{levels.map((l, index) => <div onClick={handleLevelClick(index)} key={l.name}>{l.height}</div>)}
</div>
</Layout>
)
}

export default DemoPage

В пример я добавил минимальный контрол для переключения уровня качества.

Вот использованный плеер и react-обертка. Альтернативный плеер.

И так, в чем же плюс?

Вкладка Network в панеле разработчика в браузере

Если вы откроете консоль, то увидите, что после того как браузер загрузил несколько первых сегментов видео, загрузка приостанавливается. Это позволит нам экономить трафик в тех случаях, когда пользователь открыл страницу с видео, начал просмотр видео и остановился. В этом случае нам не нужно загружать весь видеофайл целиком. Мы можем вовремя остановиться, а потом если это понадобится, загрузить остальное, если воспроизведение продолжится.