mirror of https://github.com/stashapp/stash.git
Merge pull request #79 from WithoutPants/live_transcode
Add basic live transcoding for non-streamable files
This commit is contained in:
commit
eb5970b850
|
@ -1,12 +1,14 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"io"
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"github.com/stashapp/stash/pkg/manager"
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
"github.com/stashapp/stash/pkg/ffmpeg"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -39,8 +41,49 @@ func (rs sceneRoutes) Routes() chi.Router {
|
|||
|
||||
func (rs sceneRoutes) Stream(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
|
||||
// detect if not a streamable file and try to transcode it instead
|
||||
filepath := manager.GetInstance().Paths.Scene.GetStreamPath(scene.Path, scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
|
||||
videoCodec := scene.VideoCodec.String
|
||||
hasTranscode, _ := manager.HasTranscode(scene)
|
||||
if ffmpeg.IsValidCodec(videoCodec) || hasTranscode {
|
||||
http.ServeFile(w, r, filepath)
|
||||
return
|
||||
}
|
||||
|
||||
// needs to be transcoded
|
||||
videoFile, err := ffmpeg.NewVideoFile(manager.GetInstance().FFProbePath, scene.Path)
|
||||
if err != nil {
|
||||
logger.Errorf("[stream] error reading video file: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
encoder := ffmpeg.NewEncoder(manager.GetInstance().FFMPEGPath)
|
||||
|
||||
stream, process, err := encoder.StreamTranscode(*videoFile)
|
||||
if err != nil {
|
||||
logger.Errorf("[stream] error transcoding video file: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Content-Type", "video/webm")
|
||||
|
||||
logger.Info("[stream] transcoding video file")
|
||||
|
||||
// handle if client closes the connection
|
||||
notify := r.Context().Done()
|
||||
go func() {
|
||||
<-notify
|
||||
logger.Info("[stream] client closed the connection. Killing stream process.")
|
||||
process.Kill()
|
||||
}()
|
||||
|
||||
_, err = io.Copy(w, stream)
|
||||
if err != nil {
|
||||
logger.Errorf("[stream] error serving transcoded video file: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) Screenshot(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package ffmpeg
|
||||
|
||||
import (
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
)
|
||||
|
||||
type Encoder struct {
|
||||
|
@ -60,3 +63,18 @@ func (e *Encoder) run(probeResult VideoFile, args []string) (string, error) {
|
|||
|
||||
return stdoutString, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) stream(probeResult VideoFile, args []string) (io.ReadCloser, *os.Process, error) {
|
||||
cmd := exec.Command(e.Path, args...)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if nil != err {
|
||||
logger.Error("FFMPEG stdout not available: " + err.Error())
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return stdout, cmd.Process, nil
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package ffmpeg
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type TranscodeOptions struct {
|
||||
OutputPath string
|
||||
}
|
||||
|
@ -20,3 +25,18 @@ func (e *Encoder) Transcode(probeResult VideoFile, options TranscodeOptions) {
|
|||
}
|
||||
_, _ = e.run(probeResult, args)
|
||||
}
|
||||
|
||||
func (e *Encoder) StreamTranscode(probeResult VideoFile) (io.ReadCloser, *os.Process, error) {
|
||||
args := []string{
|
||||
"-i", probeResult.Path,
|
||||
"-c:v", "libvpx-vp9",
|
||||
"-vf", "scale=iw:-2",
|
||||
"-deadline", "realtime",
|
||||
"-cpu-used", "5",
|
||||
"-crf", "30",
|
||||
"-b:v", "0",
|
||||
"-f", "webm",
|
||||
"pipe:",
|
||||
}
|
||||
return e.stream(probeResult, args)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue