mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Overhaul HLS streaming (#3274)
* Overhaul HLS streaming * Fix streaming transcode ffmpeg zombie processes * Add changelog and release notes * Documentation --------- Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
@@ -5,10 +5,10 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
"github.com/stashapp/stash/internal/static"
|
||||
"github.com/stashapp/stash/pkg/ffmpeg"
|
||||
"github.com/stashapp/stash/pkg/fsutil"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
@@ -16,58 +16,6 @@ import (
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
type StreamRequestContext struct {
|
||||
context.Context
|
||||
ResponseWriter http.ResponseWriter
|
||||
}
|
||||
|
||||
func NewStreamRequestContext(w http.ResponseWriter, r *http.Request) *StreamRequestContext {
|
||||
return &StreamRequestContext{
|
||||
Context: r.Context(),
|
||||
ResponseWriter: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *StreamRequestContext) Cancel() {
|
||||
hj, ok := (c.ResponseWriter).(http.Hijacker)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// hijack and close the connection
|
||||
conn, bw, _ := hj.Hijack()
|
||||
if conn != nil {
|
||||
if bw != nil {
|
||||
// notify end of stream
|
||||
_, err := bw.WriteString("0\r\n")
|
||||
if err != nil {
|
||||
logger.Warnf("unable to write end of stream: %v", err)
|
||||
}
|
||||
_, err = bw.WriteString("\r\n")
|
||||
if err != nil {
|
||||
logger.Warnf("unable to write end of stream: %v", err)
|
||||
}
|
||||
|
||||
// flush the buffer, but don't wait indefinitely
|
||||
timeout := make(chan struct{}, 1)
|
||||
go func() {
|
||||
_ = bw.Flush()
|
||||
close(timeout)
|
||||
}()
|
||||
|
||||
const waitTime = time.Second
|
||||
|
||||
select {
|
||||
case <-timeout:
|
||||
case <-time.After(waitTime):
|
||||
logger.Warnf("unable to flush buffer - closing connection")
|
||||
}
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func KillRunningStreams(scene *models.Scene, fileNamingAlgo models.HashAlgorithm) {
|
||||
instance.ReadLockManager.Cancel(scene.Path)
|
||||
|
||||
@@ -94,7 +42,7 @@ func (s *SceneServer) StreamSceneDirect(scene *models.Scene, w http.ResponseWrit
|
||||
fileNamingAlgo := config.GetInstance().GetVideoFileNamingAlgorithm()
|
||||
|
||||
filepath := GetInstance().Paths.Scene.GetStreamPath(scene.Path, scene.GetHash(fileNamingAlgo))
|
||||
streamRequestCtx := NewStreamRequestContext(w, r)
|
||||
streamRequestCtx := ffmpeg.NewStreamRequestContext(w, r)
|
||||
|
||||
// #2579 - hijacking and closing the connection here causes video playback to fail in Safari
|
||||
// We trust that the request context will be closed, so we don't need to call Cancel on the
|
||||
|
||||
Reference in New Issue
Block a user