05. DASH Protocol: Відкритий Стандарт
05. DASH Protocol: Відкритий Стандарт
1. Вступ: Чому виник DASH?
Проблема, яку вирішує DASH
Уявіть: це 2010 рік. У світі стрімінгу хаос:
- Apple просуває HLS (тільки для iOS/Safari)
- Microsoft має Smooth Streaming (тільки для Silverlight)
- Adobe використовує HDS (HTTP Dynamic Streaming для Flash)
Результат: Розробники змушені кодувати відео три рази для різних платформ.
Рішення: MPEG Industry Forum створив DASH (Dynamic Adaptive Streaming over HTTP) — відкритий стандарт ISO/IEC 23009-1.
- Відкритий стандарт (не належить одній компанії)
- Підтримка будь-яких кодеків (VP9, AV1, Opus)
- Універсальний DRM (Widevine, PlayReady)
- Використовується YouTube, Netflix, Amazon Prime
Аналогія: Lego Інструкція
Якщо HLS — це "зміст книги" (лінійний список сегментів), то DASH — це XML-маніфест, схожий на детальну інструкцію Lego:
- "Ось цей кубик (Representation) — для звуку 5.1"
- "Ось цей кубик — для відео 4K"
- "Ось цей кубик — для субтитрів німецькою"
- "Ти можеш зібрати з них що завгодно"
Переваги такого підходу:
- Модульність (окремо аудіо, відео, субтитри)
- Гнучкість (можна додати нові треки без перекодування всього)
- Міжнародність (багатомовний контент)
2. Архітектура DASH: MPD (Media Presentation Description)
2.1. Структура MPD
Маніфест у DASH називається .mpd (Media Presentation Description). Це XML файл.
Чому XML, а не текст як у HLS?
✅ Переваги XML
- Формальна схема (можна валідувати автоматично)
- Ієрархічна структура (Period → AdaptationSet → Representation)
- Стандартні XML-парсери в усіх мовах програмування
- Підтримка namespace (можна додавати кастомні атрибути)
❌ Недоліки XML
- Більший розмір файлу (порівняно з M3U8)
- Складніше читати очима
- Більше overhead для парсингу
2.2. Ієрархія DASH XML
Розшифровка:
- MPD (Root): Корінь документа
- Period: Часовий період (реклама, основний контент, титри)
- AdaptationSet: Група потоків одного типу (всі відео, всі аудіо)
- Representation: Конкретний варіант якості (1080p, 720p, AAC 128k)
- Segment: Фізичний файл (.m4s)
2.3. Приклад MPD
<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011"
type="static"
mediaPresentationDuration="PT10M30S"
minBufferTime="PT2S">
<Period id="main" duration="PT10M30S">
<!-- Video Adaptation Set -->
<AdaptationSet
id="video"
mimeType="video/mp4"
codecs="avc1.4d401f"
width="1920"
height="1080"
frameRate="30">
<!-- 1080p Representation -->
<Representation
id="video_1080p"
bandwidth="5000000"
width="1920"
height="1080">
<BaseURL>video/1080p/</BaseURL>
<SegmentTemplate
media="segment_$Number$.m4s"
initialization="init.mp4"
timescale="90000"
duration="540000"
startNumber="1"/>
</Representation>
<!-- 720p Representation -->
<Representation
id="video_720p"
bandwidth="2500000"
width="1280"
height="720">
<BaseURL>video/720p/</BaseURL>
<SegmentTemplate
media="segment_$Number$.m4s"
initialization="init.mp4"
timescale="90000"
duration="540000"
startNumber="1"/>
</Representation>
<!-- 480p Representation -->
<Representation
id="video_480p"
bandwidth="1000000"
width="854"
height="480">
<BaseURL>video/480p/</BaseURL>
<SegmentTemplate
media="segment_$Number$.m4s"
initialization="init.mp4"
timescale="90000"
duration="540000"
startNumber="1"/>
</Representation>
</AdaptationSet>
<!-- Audio Adaptation Set (English) -->
<AdaptationSet
id="audio_en"
mimeType="audio/mp4"
codecs="mp4a.40.2"
lang="en"
audioSamplingRate="48000">
<Representation
id="audio_en_128k"
bandwidth="128000">
<BaseURL>audio/en/</BaseURL>
<SegmentTemplate
media="segment_$Number$.m4s"
initialization="init.mp4"
timescale="48000"
duration="288000"
startNumber="1"/>
</Representation>
</AdaptationSet>
<!-- Audio Adaptation Set (Spanish) -->
<AdaptationSet
id="audio_es"
mimeType="audio/mp4"
codecs="mp4a.40.2"
lang="es"
audioSamplingRate="48000">
<Representation
id="audio_es_128k"
bandwidth="128000">
<BaseURL>audio/es/</BaseURL>
<SegmentTemplate
media="segment_$Number$.m4s"
initialization="init.mp4"
timescale="48000"
duration="288000"
startNumber="1"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>
Пояснення ключових атрибутів:
static: VOD (весь контент доступний одразу)dynamic: Live (сегменти додаються в реальному часі)
2.4. SegmentTemplate: Як генеруються URL
<SegmentTemplate
media="segment_$Number$.m4s"
initialization="init.mp4"
timescale="90000"
duration="540000"
startNumber="1"/>
Як плеєр будує URL:
- Базовий URL:
https://cdn.example.com/video/1080p/ - Ініціалізаційний сегмент (один раз):
init.mp4 - Медіа-сегменти:
$Number$замінюється на номер сегментаsegment_1.m4s,segment_2.m4s,segment_3.m4s, ...
Повні URL:
https://cdn.example.com/video/1080p/init.mp4 ← Завантажується 1 раз
https://cdn.example.com/video/1080p/segment_1.m4s
https://cdn.example.com/video/1080p/segment_2.m4s
https://cdn.example.com/video/1080p/segment_3.m4s
...
3. DASH vs HLS: Детальне Порівняння
3.1. Порівняльна таблиця
| Характеристика | HLS (Apple) | DASH (MPEG) |
|---|---|---|
| Розробник | Apple Inc. | MPEG Industry Forum |
| Стандарт | RFC 8216 (IETF) | ISO/IEC 23009-1 |
| Маніфест | .m3u8 (текстовий, M3U Extended) | .mpd (XML) |
| Кодеки | Обмежені (H.264/H.265/AAC обов'язкові для Safari) | Codec-agnostic (VP9, AV1, Opus, будь-що) |
| Сегменти | .ts (MPEG-TS) або .m4s (fMP4) | .m4s (fragmented MP4) |
| DRM | FairPlay (тільки Apple екосистема) | CENC (Common Encryption) → Widevine, PlayReady |
| Нативна підтримка iOS | ✅ Так (Safari, AVPlayer) | ❌ Потрібен dash.js або Shaka Player |
| Нативна підтримка Android | ⚠️ Частково (потрібен ExoPlayer або hls.js) | ✅ Так (через MSE - Media Source Extensions) |
| Латентність (традиційна) | 20-40 сек | 10-30 сек (краще через менший segment overhead) |
| Латентність (Low Latency) | 2-6 сек (LL-HLS, iOS 14+) | 3-5 сек (LL-DASH) |
| CDN friendly | ✅ Відмінно | ✅ Відмінно |
| Multi-audio | ⚠️ Складно (потрібен окремий плейліст) | ✅ Просто (AdaptationSet з lang атрибутом) |
| Multi-subtitle | ⚠️ Окремий WebVTT плейліст | ✅ Вбудовано в MPD |
| Екосистема | Більша (більше CDN підтримки) | Менша, але зростає |
3.2. Ключові Відмінності
DASH має Period — HLS ні
У DASH можна мати кілька Period (періодів) в одному MPD:
<MPD>
<Period id="preroll_ad" duration="PT30S">
<!-- 30-секундна реклама -->
</Period>
<Period id="main_content" duration="PT2H">
<!-- Основний фільм -->
</Period>
<Period id="credits" duration="PT5M">
<!-- Титри -->
</Period>
</MPD>
Переваги:
- Різні періоди можуть мати різні кодеки
- Легко вставити рекламу (server-side ad insertion)
- Можна змінювати набір якостей per-period
HLS еквівалент: Потрібен окремий .m3u8 для кожного періоду або використання #EXT-X-DISCONTINUITY.
DASH:
<AdaptationSet lang="en" mimeType="audio/mp4">
<Representation bandwidth="128000">...</Representation>
</AdaptationSet>
<AdaptationSet lang="es" mimeType="audio/mp4">
<Representation bandwidth="128000">...</Representation>
</AdaptationSet>
<AdaptationSet lang="uk" mimeType="audio/mp4">
<Representation bandwidth="128000">...</Representation>
</AdaptationSet>
Плеєр автоматично вибирає мову на основі browser locale.
HLS: Потрібен #EXT-X-MEDIA у Master Playlist:
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="en",NAME="English",URI="audio_en.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="es",NAME="Spanish",URI="audio_es.m3u8"
Висновок: DASH природно підтримує багатомовність.
DASH + CENC (Common Encryption):
- Один шифрований файл працює з кількома DRM (Widevine, PlayReady, FairPlay*)
- MPD містить
<ContentProtection>для кожної системи:
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" value="Widevine">
<cenc:pssh>BASE64_WIDEVINE_PSSH</cenc:pssh>
</ContentProtection>
<ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95" value="PlayReady">
<cenc:pssh>BASE64_PLAYREADY_PSSH</cenc:pssh>
</ContentProtection>
HLS + FairPlay:
- Тільки Apple екосистема
- Для Widevine потрібен окремий DASH manifest
Висновок: Netflix використовує DASH саме через DRM flexibility.
4. Створення DASH Контенту за допомогою FFmpeg
4.1. Простий DASH stream (одна якість)
ffmpeg -i input.mp4 \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k \
-f dash \
-seg_duration 6 \
-use_template 1 \
-use_timeline 0 \
output.mpd
Пояснення параметрів:
<SegmentTemplate> замість <SegmentList> (економить місце в MPD)<SegmentTimeline> (простіший MPD для VOD)Результат:
output.mpd
init-stream0.m4s ← Ініціалізаційний сегмент (відео)
init-stream1.m4s ← Ініціалізаційний сегмент (аудіо)
chunk-stream0-00001.m4s
chunk-stream0-00002.m4s
chunk-stream0-00003.m4s
...
chunk-stream1-00001.m4s ← Аудіо сегменти
chunk-stream1-00002.m4s
...
4.2. Multi-bitrate DASH (ABR)
Створимо 3 варіанти якості: 480p, 720p, 1080p.
#!/bin/bash
INPUT="movie.mp4"
OUTPUT_DIR="dash_output"
mkdir -p "$OUTPUT_DIR"
ffmpeg -i "$INPUT" \
-map 0:v -map 0:v -map 0:v -map 0:a \
\
-c:v:0 libx264 -b:v:0 1000k -s:v:0 854x480 -profile:v:0 main \
-c:v:1 libx264 -b:v:1 2500k -s:v:1 1280x720 -profile:v:1 main \
-c:v:2 libx264 -b:v:2 5000k -s:v:2 1920x1080 -profile:v:2 high \
\
-c:a aac -b:a 128k -ar 48000 \
\
-f dash \
-seg_duration 6 \
-use_template 1 \
-use_timeline 0 \
-init_seg_name 'init-$RepresentationID$.m4s' \
-media_seg_name 'chunk-$RepresentationID$-$Number%05d$.m4s' \
-adaptation_sets "id=0,streams=v id=1,streams=a" \
"$OUTPUT_DIR/manifest.mpd"
Пояснення:
-map 0:v -map 0:v -map 0:v: Створює 3 відео-потоки-map 0:a: Один аудіо-потік-c:v:0,-c:v:1,-c:v:2: Окремі налаштування для кожного відео-adaptation_sets: Групування (AdaptationSet 0 = відео, AdaptationSet 1 = аудіо)
Результат:
<MPD>
<Period>
<AdaptationSet id="0">
<Representation id="0" bandwidth="1000000" width="854" height="480">...
<Representation id="1" bandwidth="2500000" width="1280" height="720">...
<Representation id="2" bandwidth="5000000" width="1920" height="1080">...
</AdaptationSet>
<AdaptationSet id="1">
<Representation id="3" bandwidth="128000">...
</AdaptationSet>
</Period>
</MPD>
4.3. Multi-language Audio
ffmpeg -i movie.mp4 -i audio_spanish.mp3 \
-map 0:v -map 0:a -map 1:a \
\
-c:v libx264 -b:v 2500k \
-c:a aac -b:a 128k \
\
-f dash \
-seg_duration 6 \
-adaptation_sets "id=0,streams=v id=1,streams=a,lang=en id=2,streams=a,lang=es" \
output.mpd
Результат:
<AdaptationSet id="1" lang="en">
<Representation id="audio_en">...</Representation>
</AdaptationSet>
<AdaptationSet id="2" lang="es">
<Representation id="audio_es">...</Representation>
</AdaptationSet>
5. Інтеграція DASH в Браузер
5.1. Shaka Player (Google)
Чому Shaka Player?
- Розроблений Google (підтримка найкраща)
- Підтримує DRM (Widevine, PlayReady, FairPlay*)
- Вбудований ABR алгоритм
- Детальна статистика (bandwidth, buffer, dropped frames)
Встановлення:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/shaka-player@4.7/dist/shaka-player.compiled.js"></script>
</head>
<body>
<video id="video" width="640" controls></video>
<script>
const video = document.getElementById('video')
const player = new shaka.Player(video)
// DASH manifest URL
const manifestUri = 'https://cdn.example.com/manifest.mpd'
player
.load(manifestUri)
.then(() => {
console.log('Video loaded successfully!')
})
.catch((error) => {
console.error('Error loading video:', error)
})
// Відслідковування змін якості
player.addEventListener('adaptation', () => {
const tracks = player.getVariantTracks()
const activeTrack = tracks.find((t) => t.active)
console.log(`Quality: ${activeTrack.height}p, Bandwidth: ${activeTrack.bandwidth}`)
})
</script>
</body>
</html>
5.2. dash.js (Альтернатива)
dash.js — reference implementation від Dash Industry Forum.
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
<video id="video" controls></video>
<script>
const url = 'https://cdn.example.com/manifest.mpd'
const player = dashjs.MediaPlayer().create()
player.initialize(document.querySelector('#video'), url, true)
// Налаштування ABR
player.updateSettings({
streaming: {
abr: {
fetchThroughputCalculationMode: 'ewma',
bandwidthSafetyFactor: 0.9,
useDefaultABRRules: true,
},
},
})
</script>
- Shaka Player: Кращий DRM support, кращий API, активніша підтримка
- dash.js: Reference implementation (100% відповідність стандарту), детальніші налаштування ABR
6. Розширені Теми
6.1. Common Encryption (CENC) та DRM
Проблема без CENC:
У минулому кожна DRM система вимагала окремого шифрування:
- Widevine:
video_widevine.m4s - PlayReady:
video_playready.m4s - FairPlay:
video_fairplay.m4s
Результат: 3x storage, 3x bandwidth.
Рішення: CENC (Common Encryption)
Один шифрований файл, але з метаданими для кількох DRM:
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="ABCD1234..."/>
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
<!-- Widevine PSSH -->
<cenc:pssh>AAAAW3Bzc2gAAAAA7e+LqXnWSs6jyCfc...</cenc:pssh>
</ContentProtection>
<ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">
<!-- PlayReady PSSH -->
<cenc:pssh>AAACYHBzc2gAAAAAmgTweZhAQoarkuZb...</cenc:pssh>
</ContentProtection>
Як це працює:
- Сегменти шифруються AES-128-CTR з Content Key
- PSSH (Protection System Specific Header) містить інформацію для кожного DRM
- Плеєр вибирає підтримувану систему (Chrome → Widevine, Edge → PlayReady)
- Отримує ліцензію з License Server
- Розшифровує та програє
Приклад з Shaka Player:
const player = new shaka.Player(video)
player.configure({
drm: {
servers: {
'com.widevine.alpha': 'https://license.example.com/widevine',
'com.microsoft.playready': 'https://license.example.com/playready',
},
},
})
player.load('https://cdn.example.com/encrypted.mpd')
6.2. Live DASH: Dynamic MPD
Відмінності Live від VOD:
<MPD type="static" mediaPresentationDuration="PT2H15M">
<Period>
<AdaptationSet>
<Representation bandwidth="5000000">
<SegmentTemplate media="seg_$Number$.m4s" startNumber="1"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>
- Усі сегменти відомі заздалегідь
mediaPresentationDurationфіксований- Плеєр завантажує MPD один раз
<MPD type="dynamic"
availabilityStartTime="2024-02-17T12:00:00Z"
publishTime="2024-02-17T12:30:00Z"
minimumUpdatePeriod="PT5S"
timeShiftBufferDepth="PT2M">
<Period start="PT0S">
<AdaptationSet>
<Representation bandwidth="5000000">
<SegmentTemplate media="seg_$Number$.m4s"
timescale="90000"
duration="540000"
startNumber="1"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>
Ключові атрибути:
availabilityStartTime: Коли почалася трансляціяpublishTime: Коли був оновлений MPD (timestamps для кешування)minimumUpdatePeriod: Як часто плеєр має перевіряти оновлення (5 сек)timeShiftBufferDepth: DVR window (2 хвилини назад користувач може перемотати)
Як плеєр працює з Live:
- Завантажує MPD
- Розраховує
availableSegmentNumberна основіavailabilityStartTimeта поточного часу - Завантажує доступні сегменти
- Кожні
minimumUpdatePeriodсекунд оновлює MPD - Якщо є нові сегменти — завантажує їх
6.3. Low Latency DASH (LL-DASH)
Стандартна DASH латентність: 10-30 секунд
LL-DASH латентність: 3-5 секунд
Ключові зміни:
📦 Chunked Transfer Encoding
Сегменти передаються по частинах (chunks) до того, як вони повністю закодовані.
Transfer-Encoding: chunked
0A\r\n
[chunk 1 data]\r\n
0B\r\n
[chunk 2 data]\r\n
...
Плеєр починає decode одразу після отримання першого chunk.
⚡ Shorter Segments
🔄 Server Push
Приклад MPD для LL-DASH:
<MPD type="dynamic"
availabilityStartTime="2024-02-17T12:00:00Z"
suggestedPresentationDelay="PT2S"
minBufferTime="PT1S">
<ServiceDescription>
<Latency target="2000" min="1000" max="4000"/>
</ServiceDescription>
<Period>
<AdaptationSet>
<Representation>
<SegmentTemplate media="seg_$Number$.m4s" duration="90000" timescale="90000"/>
<!-- duration=90000/90000 = 1 секунда -->
</Representation>
</AdaptationSet>
</Period>
</MPD>
- dash.js 4.0+
- Shaka Player 4.2+
- Потребує HTTP/2 сервер (Nginx 1.13+, Apache 2.4.17+)
6.4. CMAF (Common Media Application Format)
Проблема: Різні формати сегментів для HLS (.ts або .m4s) та DASH (.m4s).
Рішення: CMAF — єдиний формат, сумісний з обома.
Переваги CMAF:
- Один набір сегментів для HLS та DASH
- 50% економія storage та bandwidth
- Простіший workflow (кодуємо один раз)
Як створити CMAF за допомогою FFmpeg:
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls \
-hls_segment_type fmp4 \
-hls_playlist_type vod \
output.m3u8
Результат:
output.m3u8 ← HLS manifest
output0.m4s
output1.m4s
output2.m4s
...
Створюємо DASH MPD вручну:
<MPD>
<Period>
<AdaptationSet>
<Representation>
<BaseURL>./</BaseURL>
<SegmentTemplate media="output$Number$.m4s" startNumber="0"/>
</Representation>
</AdaptationSet>
</Period>
</MPD>
Або використовуємо Shaka Packager:
packager \
in=input.mp4,stream=video,output=video.mp4 \
in=input.mp4,stream=audio,output=audio.mp4 \
--hls_master_playlist_output master.m3u8 \
--mpd_output manifest.mpd
7. Performance Optimization
7.1. Initialization Segment Optimization
Проблема: Init segment завантажується для кожної якості при переключенні.
Рішення: Об'єднаний init segment для всіх representations.
ffmpeg \
-f dash \
-single_file 1 \
-init_seg_name 'init.mp4' \
output.mpd
Результат:
- Один
init.mp4для всіх якостей - Економія: 1-2 MB при кожному переключенні якості
7.2. Byte-Range Requests
Замість окремих файлів можна зберігати всі сегменти в одному файлі та використовувати HTTP Range headers:
<SegmentList>
<Initialization sourceURL="stream.mp4" range="0-1024"/>
<SegmentURL mediaRange="1025-500000"/>
<SegmentURL mediaRange="500001-950000"/>
<SegmentURL mediaRange="950001-1400000"/>
</SegmentList>
Переваги:
- Менше HTTP запитів (один файл замість 100+ сегментів)
- Простіший storage (один файл замість тисяч)
- Ідеально для CDN (один кеш-запис)
Недоліки:
- Якщо щось псується в файлі — вся якість недоступна
- Складніше оновлювати Live контент
7.3. Server-Side Rendering: Reduce MPD Size
Великий MPD (кілька MB) може сповільнити start time.
Рішення: Генерувати MPD динамічно на сервері:
// Node.js приклад
app.get('/manifest.mpd', (req, res) => {
const userAgent = req.headers['user-agent']
const isMobile = /Mobile/.test(userAgent)
// Для мобільних: тільки 480p, 720p
// Для desktop: 720p, 1080p, 4K
const qualities = isMobile ? ['480p', '720p'] : ['720p', '1080p', '4k']
const mpd = generateMPD(qualities)
res.set('Content-Type', 'application/dash+xml')
res.send(mpd)
})
Економія: MPD розміром 500 KB замість 2 MB.
8. Troubleshooting
8.1. Типові Проблеми
Те саме, що в HLS. Додайте CORS headers:
location ~ \.(mpd|m4s|mp4)$ {
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS' always;
add_header Access-Control-Allow-Headers 'Range' always;
if ($request_method = OPTIONS) {
return 204;
}
}
Проблема: Safari НЕ має нативної підтримки DASH.
Рішення:
- Fallback на HLS:
const video = document.getElementById('video')
if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Safari: використовуємо HLS
video.src = 'https://cdn.example.com/stream.m3u8'
} else if (shaka.Player.isBrowserSupported()) {
// Chrome/Firefox: використовуємо DASH
const player = new shaka.Player(video)
player.load('https://cdn.example.com/manifest.mpd')
}
- CMAF: Один набір сегментів, два manifests (HLS + DASH).
Симптом (Live DASH):
Failed to load segment: 404 Not Found
chunk-stream0-00125.m4s
Причина: Плеєр розрахував, що сегмент вже має бути доступний, але encoder ще не створив його.
Діагностика:
Перевірте suggestedPresentationDelay у MPD:
<MPD suggestedPresentationDelay="PT10S">
Це означає: плеєр має відтворювати з затримкою 10 секунд від "live edge".
Рішення:
Збільшіть suggestedPresentationDelay до 15-20 секунд.
Причина: Різні timescale для аудіо та відео.
Діагностика:
ffprobe -show_streams chunk-stream0-00001.m4s | grep time_base
# Відео: time_base=1/90000
ffprobe -show_streams chunk-stream1-00001.m4s | grep time_base
# Аудіо: time_base=1/48000
Рішення:
У MPD переконайтесь, що timescale правильний:
<!-- Відео -->
<SegmentTemplate timescale="90000" duration="540000"/>
<!-- 540000/90000 = 6 секунд -->
<!-- Аудіо -->
<SegmentTemplate timescale="48000" duration="288000"/>
<!-- 288000/48000 = 6 секунд -->
Обидва мають бути 6 секунд.
8.2. Інструменти Діагностики
🧪 DASH Validator
Upload ваш .mpd та отримайте звіт про помилки.
📊 Shaka Player Stats
const player = new shaka.Player(video)
setInterval(() => {
const stats = player.getStats()
console.log('Bandwidth:', stats.estimatedBandwidth)
console.log('Buffer:', video.buffered.end(0) - video.currentTime)
console.log('Dropped frames:', stats.droppedFrames)
}, 1000)
🔍 Chrome Media Internals
Відкрийте chrome://media-internals/ та натисніть Play на DASH відео.
Ви побачите:
- Завантажені сегменти
- Buffer graph
- Decoder статус
- Помилки декодування
9. DASH Best Practices
1. Використовуйте CMAF для HLS + DASH
Один набір сегментів = 50% економії.
2. Налаштуйте правильні Cache Headers
location ~ \.mpd$ {
add_header Cache-Control "public, max-age=10";
}
location ~ \.(m4s|mp4)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
3. Для Live: suggestedPresentationDelay >= 10s
Захищає від 404 на сегментах.
4. DRM: Використовуйте CENC
Один шифрований файл для Widevine + PlayReady.
5. Multi-language: Окремі AdaptationSet
<AdaptationSet lang="en">...</AdaptationSet>
<AdaptationSet lang="es">...</AdaptationSet>
10. Практичні Завдання
Завдання 1: Створити Multi-bitrate DASH
Мета: Перетворити movie.mp4 на DASH з 3 якостями (480p, 720p, 1080p) та 2 мовами (англійська, іспанська).
Кроки:
- Підготуйте
audio_spanish.mp3 - Використайте FFmpeg для створення DASH
- Перевірте MPD у валідаторі
- Відкрийте в Shaka Player Demo
Критерії успіху:
- 3 відео representations
- 2 аудіо adaptationSets з
langатрибутами - ABR працює (перемикається між якостями)
Завдання 2: CMAF для HLS + DASH
Мета: Створити один набір сегментів, який працює і з HLS, і з DASH.
Кроки:
- Закодуйте відео в fMP4 (CMAF)
- Створіть HLS manifest (
master.m3u8) - Створіть DASH manifest (
manifest.mpd) - Перевірте обидва в різних плеєрах
Завдання 3: Діагностика Live DASH
Проблема: Live stream має затримку 45 секунд замість очікуваних 10.
Завдання:
- Завантажте MPD та знайдіть
suggestedPresentationDelay - Перевірте
timeShiftBufferDepth - Виміряйте encoder latency
- Знайдіть bottleneck
11. FAQ
A: Safari НЕ підтримує DASH нативно. Варіанти:
- Використовуйте Shaka Player (JavaScript polyfill)
- Fallback на HLS для Safari
- CMAF: один набір сегментів, два manifests
A:
- SegmentTemplate: Шаблон URL (
segment_$Number$.m4s). Компактний MPD. - SegmentList: Явний список усіх сегментів. Великий MPD, але гнучкіший.
- SegmentBase: Один файл з Byte-Range requests. Для VOD з великими файлами.
Рекомендація: SegmentTemplate для більшості випадків.
A:
<MPD type="dynamic" timeShiftBufferDepth="PT10M">
timeShiftBufferDepth=PT10M = користувач може перемотати на 10 хвилин назад.
Плеєр зберігає старі сегменти в буфері. Після 10 хвилин вони видаляються.
12. Резюме
🎯 Що таке DASH
- Відкритий стандарт ISO/IEC 23009-1
- Codec-agnostic (VP9, AV1, Opus)
- XML manifest (
.mpd) - Підтримка CENC DRM (Widevine, PlayReady)
📐 Архітектура
MPD
└─ Period
└─ AdaptationSet (Video)
├─ Representation (1080p)
├─ Representation (720p)
└─ Representation (480p)
└─ AdaptationSet (Audio EN)
└─ AdaptationSet (Audio ES)
⚙️ Створення
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f dash \
output.mpd
🌐 Браузер
Shaka Player або dash.js
Safari: fallback на HLS
- DASH = гнучкість (codec-agnostic, multi-language, DRM)
- HLS = simple та Apple-friendly
- Best practice: CMAF (один набір сегментів для обох)