Pelajari cara kerja HLS dari segmen hingga playlist, bagaimana FFmpeg membangun master playlist dengan beberapa variant kualitas, serta mengapa adaptive bitrate membuat streaming bisa menyesuaikan bandwidth penonton.

Pada episode 13 kalian belajar mengirim video lewat jaringan: RTMP ke platform live, SRT antar site, UDP untuk multicast. Semua itu memakai protokol yang push — encoder yang memutuskan ke mana dan kapan video dikirim. Sekarang mari kita bicarakan pendekatan yang justru kebalikannya, dan menjadi standar dunia: HTTP Live Streaming (HLS).
HLS adalah ide yang tampak sederhana tapi mengubah segalanya: potong video menjadi segmen kecil, tulis daftarnya ke sebuah playlist teks, dan layani keduanya lewat HTTP biasa. Tidak ada protokol baru, tidak ada port khusus — hanya HTTP, protokol yang sudah melewati hampir semua firewall di bumi ini. Pemutar cukup mengunduh segmen satu per satu dari daftar itu. Kita sudah menyentuh fondasinya di episode 12 (segmen) dan sekarang kita akan merakitnya menjadi sistem streaming yang utuh.
Setiap output HLS terdiri dari dua jenis file: segmen media (berisi potongan video) dan playlist (file teks berisi daftar segmen). Playlist inilah yang direquest pemutar pertama kali, dan dari playlist itulah pemutar tahu segmen mana yang harus diunduh berikutnya.
Muxer hls melakukan semua yang tadi kita kerjakan manual di episode 12 — memotong, menamai, dan menulis playlist — dalam satu perintah. Contoh paling dasar, mengemas file MP4 yang sudah ada tanpa re-encode:
ffmpeg -i input.mp4 -c copy -f hls -hls_time 6 -hls_playlist_type vod out.m3u8`-f hls{:bash}` memilih muxer HLS.-hls_time 6 menargetkan tiap segmen sekitar 6 detik. Persis seperti muxer segment, pemotongan dilakukan pada keyframe berikutnya setelah waktu itu terlewati.-hls_playlist_type vod menandai playlist sebagai Video On Demand: isinya lengkap dari awal sampai akhir dan diakhiri #EXT-X-ENDLIST. Untuk live streaming, hapus opsi ini — playlist akan menjadi jendela bergulir yang terus diperbarui.-hls_list_size 0 berarti simpan semua segmen dalam playlist. Default-nya 5, sebuah jendela bergulir untuk live; untuk VOD yang lengkap, setel ke 0.Hasilnya adalah file out.m3u8 dan segmen-segmen out0.ts, out1.ts, dan seterusnya. Isi playlist-nya kira-kira seperti ini:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.000000,
out0.ts
#EXTINF:6.000000,
out1.ts
#EXTINF:6.000000,
out2.ts
#EXT-X-ENDLISTSetiap blok #EXTINF diikuti nama file segmen dan durasinya. Pemutar membaca daftar ini dari atas, mengunduh segmen yang ditunjuk, lalu melanjutkan ke segmen berikutnya. #EXT-X-TARGETDURATION memberi tahu batas maksimum durasi segmen agar pemutar bisa menyiapkan buffer yang cukup. Segmen-segmen ini persis seperti yang kita pelajari di episode 12: harus bisa didekode mandiri, karena pemutar men-decode tiap segmen secara independen.
Tip
Re-encode biasanya tidak bisa dihindari karena dua alasan: segmen HLS harus berisi keyframe di awal (tidak semua MP4 sudah demikian), dan format container standar HLS adalah MPEG-TS yang parameter-nya harus konsisten. Jika -c copy menghasilkan segmen yang gagal diputar, tambahkan encode dengan -c:v libx264 -c:a aac dan -hls_time yang merupakan kelipatan interval keyframe (-g), persis seperti pola -g 60 untuk 30 fps dari episode 13.
Standar asli HLS memakai MPEG-TS karena alasan historis, tapi ada mode yang lebih modern: segmen fragmented MP4 (fMP4). Dengan fMP4, inisialisasi codec ditulis sekali ke sebuah file init kecil (init.mp4), lalu segmen-segmen berikutnya hanya berisi data fragment. Ukuran file menjadi lebih kecil dan kompatibilitas dengan era modern lebih baik — inilah yang dipakai layanan streaming besar saat ini.
ffmpeg -i input.mp4 -c copy -f hls -hls_time 6 -hls_segment_type fmp4 -hls_playlist_type vod out.m3u8Perhatikan dua file yang dihasilkan: out.m3u8 dan init.mp4. Pemutar mengunduh init.mp4 terlebih dahulu untuk memahami format stream, lalu memutar segmen-segmen fMP4 di atasnya. Mode fMP4 membutuhkan HLS versi 7 ke atas — ditandai dengan #EXT-X-VERSION:7 di dalam playlist, yang otomatis ditulis FFmpeg.
Sejauh ini kita baru membuat satu versi video. HLS menjadi adaptive ketika ada lebih dari satu versi: pemutar memilih versi mana yang akan diunduh berdasarkan bandwidth dan ukuran layar perangkat. Versi-versi ini disebut variant (atau rendisi), dan daftar yang mereferensikan semua variant disebut master playlist.
Satu instance muxer hls bisa membangun beberapa variant sekaligus menggunakan -var_stream_map dan -master_pl_name. Perhatikan cara memetakan stream-nya: tiga output video diambil dari input yang sama, masing-masing dengan bitrate dan resolusi berbeda, sementara audio cukup di-encode sekali dan dibagikan ke semua variant:
ffmpeg -i input.mp4 \
-map v:0 -c:v:0 libx264 -b:v:0 5000k -maxrate:0 5500k -bufsize:0 8000k -s:v:0 1920x1080 \
-map v:0 -c:v:1 libx264 -b:v:1 2500k -maxrate:1 2800k -bufsize:1 4000k -s:v:1 1280x720 \
-map v:0 -c:v:2 libx264 -b:v:2 1000k -maxrate:2 1100k -bufsize:2 1600k -s:v:2 854x480 \
-map a:0 -c:a aac -b:a 128k \
-f hls -hls_time 6 -hls_playlist_type vod -hls_flags independent_segments \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
var%v/index.m3u8Mari kita bedah:
-map v:0 diulang tiga kali dengan -c:v:0, -c:v:1, -c:v:2 — tiga encoder video dari input yang sama, masing-masing dengan bitrate (-b:v:N), batas bitrate (-maxrate), ukuran buffer (-bufsize), dan resolusi (-s) sendiri.-map a:0 -c:a aac meng-encode audio sekali saja, dan -var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" menyatakan bahwa ketiga variant berbagi audio yang sama.var%v/index.m3u8 adalah pola nama playlist per variant; %v digantikan nomor variant. Hasilnya var0/index.m3u8, var1/index.m3u8, var2/index.m3u8.-master_pl_name master.m3u8 menulis master playlist yang mereferensikan ketiganya.-hls_flags independent_segments menambahkan penanda bahwa semua segmen bisa didekode independen — syarat penting untuk switching antar kualitas yang mulus.Master playlist yang dihasilkan kira-kira seperti ini:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5600000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2"
var0/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=3100000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2"
var1/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=854x480,CODECS="avc1.4d401f,mp4a.40.2"
var2/index.m3u8Inilah file yang kalian berikan kepada pemutar. Ketika bandwidth penonton turun, pemutar bergeser ke variant dengan BANDWIDTH yang lebih rendah di tengah-tengah playback tanpa restart — itu sihir adaptive streaming.
Kunci seluruh sistem ini adalah atribut BANDWIDTH di master playlist: perkiraan peak bitrate sebuah variant. Pemutar menjadikannya acuan memilih variant — memilih variant dengan BANDWIDTH terbesar yang masih di bawah kecepatan koneksi penonton. Maka akurasi angka ini sangat menentukan kualitas pengalaman.
Cara muxer hls menghitung BANDWIDTH telah berubah seiring versi. Dulu ia menebak dari bitrate nominal yang kalian berikan, ditambah faktor 10 persen untuk overhead container. Sejak FFmpeg 7, untuk VOD dengan encode VBR, ia menghitung dari ukuran aktual tiap segmen — bitrate puncak dari segmen yang benar-benar dihasilkan ditulis sebagai BANDWIDTH, dan rata-rata keseluruhan sebagai AVERAGE-BANDWIDTH. Ini membuat angka BANDWIDTH menjadi lebih jujur untuk VBR.
Satu kesalahpahaman yang perlu diluruskan: mode bitrate (CBR atau VBR) tidak diatur oleh muxer HLS. Kalian tidak akan menemukan opsi bernama hls_bitrate_mode — yang ada adalah bitrate_mode di level encoder, tempat keputusan itu sebenarnya diambil:
libx264 memakai kombinasi -b:v + -maxrate + -bufsize, yang menghasilkan constrained VBR — bitrate mengambang tapi dibatasi.-rc vbr atau -rc cbr.bitrate_mode dengan nilai vbr, cbr, atau cq (constant quality).Tugas muxer hls hanya melaporkan berapa BANDWIDTH yang dihasilkan encoder. Untuk hasil yang stabil, pilih mode bitrate di level encoder sesuai kebutuhan: VBR untuk kualitas terbaik pada ukuran tertentu, CBR untuk prediktabilitas bandwidth yang ketat.
Important
Pemilihan variant terjadi pada batas segmen — pemutar tidak akan mengganti kualitas di tengah segmen. Karena itu semua variant harus keyframe-aligned: keyframe muncul pada timestamp yang sama di semua variant, sehingga batas segmen (yang selalu jatuh di keyframe) sejajar antar variant. Itulah mengapa contoh di atas memakai -hls_flags independent_segments dan -hls_time yang sama untuk semua variant — penyelarasan ini membuat switching kualitas terasa mulus dan instan.
Warning
Saat memakai -c copy untuk HLS, master playlist yang valid butuh informasi codec dan bitrate yang hanya tersedia jika stream di-parse. FFmpeg akan memberi peringatan "Bandwidth info not available" dan menolak menulis master playlist bila -b:v dan -b:a tidak disebutkan. Jika kalian benar-benar hanya mem-repackage, tetap sertakan -b:v dan -b:a sebagai estimasi agar master playlist bisa ditulis.
Pada episode 14 ini kalian telah merakit fondasi dari episode 12 dan 13 menjadi sistem streaming standar dunia: memahami anatomi HLS sebagai kombinasi segmen dan playlist, menghasilkan media playlist dengan -f hls, memakai segmen fMP4 untuk efisiensi modern, membangun master playlist dengan -var_stream_map dan -master_pl_name, serta memahami bagaimana atribut BANDWIDTH dihitung dan mengapa mode bitrate sebenarnya hidup di level encoder, bukan di muxer.
Poin kunci yang perlu dibawa pulang:
-hls_playlist_type vod untuk VOD lengkap; tanpa opsi itu, playlist menjadi jendela live bergulir.-hls_segment_type fmp4 menghasilkan segmen fragmented MP4 yang lebih efisien.-var_stream_map bisa menghasilkan banyak variant plus master playlist.Semua encoding yang kita lakukan sejauh ini masih berjalan di CPU. Untuk resolusi tinggi, framerate tinggi, atau jumlah variant yang banyak, CPU akan menjerit — dan di situlah GPU memasuki permainan.
Di episode 15 berikutnya kita akan membahas Hardware Acceleration — NVENC, VAAPI, QSV, AMF, VideoToolbox, hingga tren 2026 dengan encoder Vulkan dan D3D12. Pastikan tetap semangat!