2026-08-26 02:16:50 -04:00
|
|
|
diff --git a/transcoder/handler.go b/transcoder/handler.go
|
|
|
|
|
--- a/transcoder/handler.go
|
|
|
|
|
+++ b/transcoder/handler.go
|
|
|
|
|
@@ -37,6 +37,14 @@ func NewHandler(c *Config) *Handler {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS")
|
|
|
|
|
+ w.Header().Set("Access-Control-Allow-Headers", "Range, Content-Type")
|
|
|
|
|
+ if r.Method == http.MethodOptions {
|
|
|
|
|
+ w.WriteHeader(http.StatusNoContent)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
// Check version if monitoring is enabled
|
|
|
|
|
if h.c.VersionMonitor && !h.versionOk(w, r) {
|
|
|
|
|
return
|
2026-08-26 02:33:58 -04:00
|
|
|
@@ -55,15 +63,15 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Serve actual file from manager
|
|
|
|
|
- if len(parts) < 3 {
|
|
|
|
|
+ if len(parts) < 5 || parts[0] != "vod" {
|
|
|
|
|
log.Println("Invalid URL", url)
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get streamid and chunk
|
|
|
|
|
- streamid := parts[0]
|
|
|
|
|
- path := "/" + strings.Join(parts[1:len(parts)-1], "/")
|
|
|
|
|
+ streamid := parts[1]
|
|
|
|
|
+ path := "/" + strings.Join(parts[2:len(parts)-1], "/")
|
|
|
|
|
chunk := parts[len(parts)-1]
|
|
|
|
|
|
|
|
|
|
// Check if POST request to create temp file
|
2026-08-26 03:38:24 -04:00
|
|
|
@@ -133,10 +141,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get existing manager or create new one
|
|
|
|
|
- manager := h.getManager(path, streamid)
|
|
|
|
|
- if manager == nil {
|
|
|
|
|
- manager = h.createManager(path, streamid)
|
|
|
|
|
- }
|
|
|
|
|
+ manager := h.getOrCreateManager(path, streamid)
|
|
|
|
|
|
|
|
|
|
// Failed to create manager
|
|
|
|
|
if manager == nil {
|
|
|
|
|
@@ -166,33 +172,29 @@ func (h *Handler) versionOk(w http.ResponseWriter, r *http.Request) bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-func (h *Handler) getManager(path string, streamid string) *Manager {
|
|
|
|
|
- h.mutex.RLock()
|
|
|
|
|
- defer h.mutex.RUnlock()
|
|
|
|
|
-
|
|
|
|
|
- m := h.managers[streamid]
|
|
|
|
|
- if m == nil || m.path != path {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
- return m
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (h *Handler) createManager(path string, streamid string) *Manager {
|
|
|
|
|
+func (h *Handler) getOrCreateManager(path string, streamid string) *Manager {
|
|
|
|
|
+ // Lookup and creation must be atomic. Master, variant, and segment requests
|
|
|
|
|
+ // commonly arrive together; concurrent creators share a tempDir, and the
|
|
|
|
|
+ // losing manager's Destroy would delete the winner's active segment files.
|
|
|
|
|
+ h.mutex.Lock()
|
|
|
|
|
+ defer h.mutex.Unlock()
|
|
|
|
|
+
|
|
|
|
|
+ old := h.managers[streamid]
|
|
|
|
|
+ if old != nil && old.path == path {
|
|
|
|
|
+ return old
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
manager, err := NewManager(h.c, path, streamid, h.close)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Println("Error creating manager", err)
|
|
|
|
|
freeIfTemp(path)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- h.mutex.Lock()
|
|
|
|
|
- defer h.mutex.Unlock()
|
|
|
|
|
-
|
|
|
|
|
- old := h.managers[streamid]
|
|
|
|
|
if old != nil {
|
|
|
|
|
old.Destroy()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h.managers[streamid] = manager
|
|
|
|
|
return manager
|
|
|
|
|
}
|
2026-08-26 02:16:50 -04:00
|
|
|
diff --git a/transcoder/stream.go b/transcoder/stream.go
|
|
|
|
|
--- a/transcoder/stream.go
|
|
|
|
|
+++ b/transcoder/stream.go
|
|
|
|
|
@@ -370,8 +370,12 @@ func (s *Stream) transcodeArgs(startAt float64, isHls bool) []string {
|
|
|
|
|
// Check whether hwaccel should be used
|
|
|
|
|
if s.c.VAAPI {
|
|
|
|
|
CV = ENCODER_VAAPI
|
|
|
|
|
- extra := "-hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -init_hw_device vaapi=memories:/dev/dri/renderD128 -filter_hw_device memories"
|
|
|
|
|
+ extra := "-init_hw_device vaapi=memories:/dev/dri/renderD128 -filter_hw_device memories"
|
|
|
|
|
args = append(args, strings.Split(extra, " ")...)
|
|
|
|
|
+ if s.m.probe.CodecName == CODEC_H264 {
|
|
|
|
|
+ extra = "-hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi"
|
|
|
|
|
+ args = append(args, strings.Split(extra, " ")...)
|
|
|
|
|
+ }
|
|
|
|
|
} else if s.c.NVENC {
|
|
|
|
|
CV = ENCODER_NVENC
|
|
|
|
|
extra := "-hwaccel cuda"
|
|
|
|
|
@@ -397,7 +401,11 @@ func (s *Stream) transcodeArgs(startAt float64, isHls bool) []string {
|
|
|
|
|
scalerArgs = append(scalerArgs, "force_original_aspect_ratio=decrease")
|
|
|
|
|
|
|
|
|
|
if CV == ENCODER_VAAPI {
|
|
|
|
|
- format = "format=nv12|vaapi,hwupload"
|
|
|
|
|
+ if s.m.probe.CodecName == CODEC_H264 {
|
|
|
|
|
+ format = "format=nv12|vaapi,hwupload"
|
|
|
|
|
+ } else {
|
|
|
|
|
+ format = "format=nv12,hwupload"
|
|
|
|
|
+ }
|
|
|
|
|
scaler = "scale_vaapi"
|
|
|
|
|
scalerArgs = append(scalerArgs, "format=nv12")
|
|
|
|
|
} else if CV == ENCODER_NVENC {
|
2026-08-27 10:16:45 -04:00
|
|
|
@@ -509,6 +517,13 @@ func (s *Stream) transcodeArgs(startAt float64, isHls bool) []string {
|
|
|
|
|
// Audio output specs
|
|
|
|
|
args = append(args, []string{
|
|
|
|
|
"-map", "0:a:0?",
|
|
|
|
|
"-c:a", "aac",
|
|
|
|
|
+ // ffmpeg decodes AC-3/DTS 5.1 as layout "5.1(side)", which the AAC
|
|
|
|
|
+ // encoder cannot express as a standard channel_configuration, so it
|
|
|
|
|
+ // emits a PCE and sets channel_configuration=0. hls.js does not parse
|
|
|
|
|
+ // the PCE, writes channelCount=0 into the fMP4 init segment, and every
|
|
|
|
|
+ // browser then rejects the audio SourceBuffer. Restricting to standard
|
|
|
|
|
+ // layouts maps 5.1(side) -> 5.1 and leaves mono/stereo untouched.
|
|
|
|
|
+ "-af", "aformat=channel_layouts=mono|stereo|5.1",
|
|
|
|
|
}...)
|
|
|
|
|
|
|
|
|
|
return args
|