Content-Type: video/mp4 and support Range requests| Segment | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| Bandwidth | Fast | Fast | Drops | Slow | Slow | Recovers | Fast |
| Quality | 1080p | 1080p | 480p | potato | potato | 480p | 1080p |
.m3u8 playlists. Segments are commonly .ts files.mpd filemaster.m3u8 lists each rendition
1/index.m3u8 lists the segments of the 360p rendition
#EXTINF is the duration of the next segment in seconds#EXT-X-ENDLIST means there are no more segmentsGET /public/videos/abc123/master.m3u8 Pick a rendition
GET /public/videos/abc123/1/index.m3u8 Start with 360p
GET /public/videos/abc123/1/index0.ts
GET /public/videos/abc123/1/index1.ts Bandwidth looks good
GET /public/videos/abc123/0/index.m3u8 Switch to 720p
GET /public/videos/abc123/0/index2.tsfunc MP4ToHLS(inputPath string, outputDir string) error {
return exec.Command("ffmpeg", "-i", inputPath,
"-map", "0:v:0", "-map", "0:a:0", "-map", "0:v:0", "-map", "0:a:0",
"-filter:v:0", "scale=-2:720", "-b:v:0", "2500k",
"-filter:v:1", "scale=-2:360", "-b:v:1", "800k",
"-f", "hls", "-hls_playlist_type", "vod",
"-master_pl_name", "master.m3u8",
"-var_stream_map", "v:0,a:0 v:1,a:1",
outputDir+"/%v/index.m3u8",
).Run()
}-i is the input file-map selects streams from the input for the output
0:v:0 is the first video stream of the first (only) input. 0:a:0 is its first audio stream0:a:0 matches nothing and ffmpeg failsfunc MP4ToHLS(inputPath string, outputDir string) error {
return exec.Command("ffmpeg", "-i", inputPath,
"-map", "0:v:0", "-map", "0:a:0", "-map", "0:v:0", "-map", "0:a:0",
"-filter:v:0", "scale=-2:720", "-b:v:0", "2500k",
"-filter:v:1", "scale=-2:360", "-b:v:1", "800k",
"-f", "hls", "-hls_playlist_type", "vod",
"-master_pl_name", "master.m3u8",
"-var_stream_map", "v:0,a:0 v:1,a:1",
outputDir+"/%v/index.m3u8",
).Run()
}-2 for the width: Compute the width that preserves the aspect ratio
func MP4ToHLS(inputPath string, outputDir string) error {
return exec.Command("ffmpeg", "-i", inputPath,
"-map", "0:v:0", "-map", "0:a:0", "-map", "0:v:0", "-map", "0:a:0",
"-filter:v:0", "scale=-2:720", "-b:v:0", "2500k",
"-filter:v:1", "scale=-2:360", "-b:v:1", "800k",
"-f", "hls", "-hls_playlist_type", "vod",
"-master_pl_name", "master.m3u8",
"-var_stream_map", "v:0,a:0 v:1,a:1",
outputDir+"/%v/index.m3u8",
).Run()
}-f hls: Output HLS-hls_playlist_type vod: Video on Demand
#EXT-X-ENDLIST-master_pl_name: Also write a master playlist named master.m3u8func MP4ToHLS(inputPath string, outputDir string) error {
return exec.Command("ffmpeg", "-i", inputPath,
"-map", "0:v:0", "-map", "0:a:0", "-map", "0:v:0", "-map", "0:a:0",
"-filter:v:0", "scale=-2:720", "-b:v:0", "2500k",
"-filter:v:1", "scale=-2:360", "-b:v:1", "800k",
"-f", "hls", "-hls_playlist_type", "vod",
"-master_pl_name", "master.m3u8",
"-var_stream_map", "v:0,a:0 v:1,a:1",
outputDir+"/%v/index.m3u8",
).Run()
}-var_stream_map: Group the streams into renditions
%v in the output path is replaced by the rendition number
outputDir/0/index.m3u8 and outputDir/1/index.m3u8Run waits until ffmpeg finishes and returns an error if it failedfunc MP4ToHLS(inputPath string, outputDir string) error {
return exec.Command("ffmpeg", "-i", inputPath,
"-map", "0:v:0", "-map", "0:a:0", "-map", "0:v:0", "-map", "0:a:0",
"-filter:v:0", "scale=-2:720", "-b:v:0", "2500k",
"-filter:v:1", "scale=-2:360", "-b:v:1", "800k",
"-f", "hls", "-hls_playlist_type", "vod",
"-master_pl_name", "master.m3u8",
"-var_stream_map", "v:0,a:0 v:1,a:1",
outputDir+"/%v/index.m3u8",
).Run()
}| Extension | MIME type |
|---|---|
.m3u8 |
application/vnd.apple.mpegurl |
.ts |
video/mp2t |
/public/videos/abc123/0/index0.tsmaster.m3u8 in your database as the video's hls_path<img> for video<video> element!controls: Displays the control buttons for the userautoplay: Plays on page load [if allowed by the browser]muted: Mute the audio (Required in Chromium for autoplay)<source> element
src of an <img>src on the video element
<video> element
<video> elementlayout.htmlhls_path, play it with hls.js