Full m3u8 generation
This commit is contained in:
@@ -1,5 +1,83 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
func RegisterHlsEndpoints() {
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterHlsEndpoints() {
|
||||||
|
http.HandleFunc("/hls/index.m3u8", EndpointHlsM3U8)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: endpoint for clients to query a video's:
|
||||||
|
video tracks,
|
||||||
|
audio tracks,
|
||||||
|
captions
|
||||||
|
Then add support to existing endpoints for specifiying these 3 options
|
||||||
|
*/
|
||||||
|
|
||||||
|
func EndpointHlsM3U8(w http.ResponseWriter, r *http.Request) {
|
||||||
|
//TODO: clean up this mess
|
||||||
|
options := strings.Split(strings.Split(strings.Replace(r.URL.String(), "%20", " ", -1), "?")[1], "&")
|
||||||
|
|
||||||
|
//TODO: make the order of options not hardcoded
|
||||||
|
libPathName := strings.TrimPrefix(options[0], "lib=")
|
||||||
|
|
||||||
|
var lib Library
|
||||||
|
|
||||||
|
for _, l := range Libraries {
|
||||||
|
if l.PathName == libPathName {
|
||||||
|
lib = l
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := lib.Path + strings.TrimPrefix(options[1], "path=")
|
||||||
|
|
||||||
|
ffprobe := exec.Command(
|
||||||
|
"ffprobe",
|
||||||
|
"-v", "error",
|
||||||
|
"-show_entries", "format=duration",
|
||||||
|
"-of", "default=noprint_wrappers=1:nokey=1",
|
||||||
|
filePath,
|
||||||
|
)
|
||||||
|
|
||||||
|
var ffprobeStdout bytes.Buffer
|
||||||
|
ffprobe.Stdout = &ffprobeStdout
|
||||||
|
|
||||||
|
err := ffprobe.Run()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileLenStr := strings.TrimSuffix(ffprobeStdout.String(), "\n")
|
||||||
|
fileLenFloat, err := strconv.ParseFloat(fileLenStr, 64)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileLenFloat = math.Ceil(fileLenFloat/6.0) * 6.0
|
||||||
|
fileLenInt := int(fileLenFloat)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/vnd.apple.mpegurl")
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "#EXTM3U")
|
||||||
|
fmt.Fprintln(w, "#EXT-X-VERSION:7")
|
||||||
|
//TODO: make this configurable
|
||||||
|
fmt.Fprintln(w, "#EXT-X-TARGETDURATION:6")
|
||||||
|
fmt.Fprintln(w, "#EXT-X-MEDIA-SEQUENCE:0")
|
||||||
|
|
||||||
|
for i := 0; i < fileLenInt/6; i++ {
|
||||||
|
fmt.Fprintln(w, "#EXTINF:6.0,")
|
||||||
|
fmt.Fprintf(w, "/hls/segment/%d.mp4?lib=%s&path=%s\n", i, lib.PathName, strings.TrimPrefix(options[1], "path="))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "#EXT-X-ENDLIST")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user