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 @@ -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 @@ -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 } 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 {