You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.0 KiB
108 lines
3.0 KiB
package ffmpeg |
|
|
|
import ( |
|
"bytes" |
|
"io" |
|
"os" |
|
"path/filepath" |
|
"strconv" |
|
"strings" |
|
|
|
"net/http" |
|
|
|
"github.com/owncast/owncast/config" |
|
"github.com/owncast/owncast/utils" |
|
log "github.com/sirupsen/logrus" |
|
) |
|
|
|
// FileWriterReceiverServiceCallback are to be fired when transcoder responses are written to disk. |
|
type FileWriterReceiverServiceCallback interface { |
|
SegmentWritten(localFilePath string) |
|
VariantPlaylistWritten(localFilePath string) |
|
MasterPlaylistWritten(localFilePath string) |
|
} |
|
|
|
// FileWriterReceiverService accepts transcoder responses via HTTP and fires the callbacks. |
|
type FileWriterReceiverService struct { |
|
callbacks FileWriterReceiverServiceCallback |
|
} |
|
|
|
// SetupFileWriterReceiverService will start listening for transcoder responses. |
|
func (s *FileWriterReceiverService) SetupFileWriterReceiverService(callbacks FileWriterReceiverServiceCallback) { |
|
s.callbacks = callbacks |
|
|
|
httpServer := http.NewServeMux() |
|
httpServer.HandleFunc("/", s.uploadHandler) |
|
|
|
localListenerAddress := "127.0.0.1:" + strconv.Itoa(config.Config.GetPublicWebServerPort()+1) |
|
|
|
go func() { |
|
if err := http.ListenAndServe(localListenerAddress, httpServer); err != nil { |
|
log.Fatal(err) |
|
} |
|
}() |
|
|
|
log.Traceln("Transcoder response listening on: " + localListenerAddress) |
|
} |
|
|
|
func (s *FileWriterReceiverService) uploadHandler(w http.ResponseWriter, r *http.Request) { |
|
if r.Method != "PUT" { |
|
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) |
|
return |
|
} |
|
|
|
path := r.URL.Path |
|
writePath := filepath.Join(config.PrivateHLSStoragePath, path) |
|
|
|
var buf bytes.Buffer |
|
_, _ = io.Copy(&buf, r.Body) |
|
data := buf.Bytes() |
|
|
|
f, err := os.Create(writePath) |
|
if err != nil { |
|
returnError(err, w) |
|
return |
|
} |
|
|
|
defer f.Close() |
|
_, err = f.Write(data) |
|
if err != nil { |
|
returnError(err, w) |
|
return |
|
} |
|
|
|
s.fileWritten(writePath) |
|
w.WriteHeader(http.StatusOK) |
|
} |
|
|
|
var _inWarningState = false |
|
|
|
func (s *FileWriterReceiverService) fileWritten(path string) { |
|
index := utils.GetIndexFromFilePath(path) |
|
|
|
if utils.GetRelativePathFromAbsolutePath(path) == "hls/stream.m3u8" { |
|
s.callbacks.MasterPlaylistWritten(path) |
|
} else if strings.HasSuffix(path, ".ts") { |
|
performanceMonitorKey := "segmentWritten-" + index |
|
averagePerformance := utils.GetAveragePerformance(performanceMonitorKey) |
|
|
|
utils.StartPerformanceMonitor(performanceMonitorKey) |
|
s.callbacks.SegmentWritten(path) |
|
|
|
if averagePerformance != 0 && averagePerformance > float64(config.Config.GetVideoSegmentSecondsLength())*1.1 { |
|
if !_inWarningState { |
|
log.Warnln("slow encoding for variant", index, "if this continues you may see buffering or errors. troubleshoot this issue by visiting https://owncast.online/docs/troubleshooting/") |
|
_inWarningState = true |
|
} |
|
} else { |
|
_inWarningState = false |
|
} |
|
} else if strings.HasSuffix(path, ".m3u8") { |
|
s.callbacks.VariantPlaylistWritten(path) |
|
} |
|
} |
|
|
|
func returnError(err error, w http.ResponseWriter) { |
|
log.Errorln(err) |
|
http.Error(w, http.StatusText(http.StatusInternalServerError)+": "+err.Error(), http.StatusInternalServerError) |
|
}
|
|
|