--- name: Adaptive Bitrate Streaming description: Automatically adjusting video quality based on network conditions using HLS, DASH protocols and player implementation for smooth playback and optimal user experience. --- # Adaptive Bitrate Streaming > **Current Level:** Advanced > **Domain:** Video Streaming / Media --- ## Overview Adaptive Bitrate (ABR) streaming automatically adjusts video quality based on network conditions. This guide covers HLS, DASH, and player implementation for building video streaming solutions that provide smooth playback across varying network conditions. --- ## ABR Concepts ``` Network Speed Detection → Quality Selection → Seamless Switching ``` **Benefits:** - Smooth playback - Reduced buffering - Optimal quality - Better user experience ## HLS (HTTP Live Streaming) ### Master Playlist ```m3u8 #EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2" 1080p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2" 720p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1500000,RESOLUTION=854x480,CODECS="avc1.64001e,mp4a.40.2" 480p/playlist.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360,CODECS="avc1.64001e,mp4a.40.2" 360p/playlist.m3u8 ``` ### Media Playlist ```m3u8 #EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:10 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:10.0, segment_0000.ts #EXTINF:10.0, segment_0001.ts #EXTINF:10.0, segment_0002.ts #EXTINF:10.0, segment_0003.ts #EXT-X-ENDLIST ``` ## Creating ABR Streams with FFmpeg ```bash # Create HLS with multiple bitrates ffmpeg -i input.mp4 \ -filter_complex \ "[0:v]split=4[v1][v2][v3][v4]; \ [v1]scale=w=1920:h=1080[v1out]; \ [v2]scale=w=1280:h=720[v2out]; \ [v3]scale=w=854:h=480[v3out]; \ [v4]scale=w=640:h=360[v4out]" \ -map "[v1out]" -c:v:0 libx264 -b:v:0 5M -maxrate:v:0 5M -bufsize:v:0 10M \ -map "[v2out]" -c:v:1 libx264 -b:v:1 3M -maxrate:v:1 3M -bufsize:v:1 6M \ -map "[v3out]" -c:v:2 libx264 -b:v:2 1.5M -maxrate:v:2 1.5M -bufsize:v:2 3M \ -map "[v4out]" -c:v:3 libx264 -b:v:3 800k -maxrate:v:3 800k -bufsize:v:3 1.6M \ -map a:0 -c:a:0 aac -b:a:0 128k \ -map a:0 -c:a:1 aac -b:a:1 128k \ -map a:0 -c:a:2 aac -b:a:2 96k \ -map a:0 -c:a:3 aac -b:a:3 64k \ -f hls \ -hls_time 6 \ -hls_playlist_type vod \ -hls_flags independent_segments \ -hls_segment_type mpegts \ -hls_segment_filename "stream_%v/data%03d.ts" \ -master_pl_name master.m3u8 \ -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2 v:3,a:3" \ stream_%v.m3u8 ``` ## DASH (MPEG-DASH) ### MPD Manifest ```xml 1080p/ 720p/ audio/ ``` ### Creating DASH with FFmpeg ```bash ffmpeg -i input.mp4 \ -map 0:v -map 0:a \ -c:v libx264 -c:a aac \ -b:v:0 5M -s:v:0 1920x1080 \ -b:v:1 3M -s:v:1 1280x720 \ -b:v:2 1.5M -s:v:2 854x480 \ -b:a 128k \ -f dash \ -seg_duration 6 \ -use_template 1 \ -use_timeline 1 \ -init_seg_name 'init-$RepresentationID$.m4s' \ -media_seg_name 'chunk-$RepresentationID$-$Number%05d$.m4s' \ manifest.mpd ``` ## Player Implementation ### Video.js ```typescript // components/VideoPlayer.tsx import { useEffect, useRef } from 'react'; import videojs from 'video.js'; import 'video.js/dist/video-js.css'; export function VideoPlayer({ src }: { src: string }) { const videoRef = useRef(null); const playerRef = useRef(null); useEffect(() => { if (!videoRef.current) return; const player = videojs(videoRef.current, { controls: true, autoplay: false, preload: 'auto', fluid: true, sources: [{ src, type: 'application/x-mpegURL' // HLS }] }); playerRef.current = player; // Quality selection player.on('loadedmetadata', () => { const qualityLevels = player.qualityLevels(); qualityLevels.on('addqualitylevel', (event: any) => { console.log('Quality level added:', event.qualityLevel); }); qualityLevels.on('change', () => { console.log('Quality changed to:', qualityLevels[qualityLevels.selectedIndex]); }); }); return () => { if (playerRef.current) { playerRef.current.dispose(); } }; }, [src]); return (
); } ``` ### hls.js ```typescript // components/HLSPlayer.tsx import { useEffect, useRef } from 'react'; import Hls from 'hls.js'; export function HLSPlayer({ src }: { src: string }) { const videoRef = useRef(null); const hlsRef = useRef(null); useEffect(() => { if (!videoRef.current) return; if (Hls.isSupported()) { const hls = new Hls({ enableWorker: true, lowLatencyMode: true, backBufferLength: 90 }); hls.loadSource(src); hls.attachMedia(videoRef.current); hls.on(Hls.Events.MANIFEST_PARSED, () => { console.log('Manifest loaded, levels:', hls.levels); }); hls.on(Hls.Events.LEVEL_SWITCHED, (event, data) => { console.log('Level switched to:', data.level); }); hls.on(Hls.Events.ERROR, (event, data) => { if (data.fatal) { switch (data.type) { case Hls.ErrorTypes.NETWORK_ERROR: console.error('Network error'); hls.startLoad(); break; case Hls.ErrorTypes.MEDIA_ERROR: console.error('Media error'); hls.recoverMediaError(); break; default: hls.destroy(); break; } } }); hlsRef.current = hls; } else if (videoRef.current.canPlayType('application/vnd.apple.mpegurl')) { // Native HLS support (Safari) videoRef.current.src = src; } return () => { if (hlsRef.current) { hlsRef.current.destroy(); } }; }, [src]); return (