diff --git a/config/config.go b/config/config.go index ea3e2bcf2..db0a3be8d 100644 --- a/config/config.go +++ b/config/config.go @@ -5,10 +5,9 @@ import ( "fmt" "io/ioutil" + "github.com/gabek/owncast/utils" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" - - "github.com/gabek/owncast/utils" ) //Config contains a reference to the configuration @@ -45,10 +44,11 @@ type socialHandle struct { } type videoSettings struct { - ChunkLengthInSeconds int `yaml:"chunkLengthInSeconds"` - StreamingKey string `yaml:"streamingKey"` - StreamQualities []StreamQuality `yaml:"streamQualities"` - OfflineContent string `yaml:"offlineContent"` + ChunkLengthInSeconds int `yaml:"chunkLengthInSeconds"` + StreamingKey string `yaml:"streamingKey"` + StreamQualities []StreamQuality `yaml:"streamQualities"` + OfflineContent string `yaml:"offlineContent"` + HighestQualityStreamIndex int `yaml"-"` } // StreamQuality defines the specifics of a single HLS stream variant. @@ -106,6 +106,8 @@ func (c *config) load(filePath string) error { return err } + c.VideoSettings.HighestQualityStreamIndex = findHighestQuality(c.VideoSettings.StreamQualities) + return nil } diff --git a/config/configUtils.go b/config/configUtils.go new file mode 100644 index 000000000..f15a443a0 --- /dev/null +++ b/config/configUtils.go @@ -0,0 +1,34 @@ +package config + +import "sort" + +func findHighestQuality(qualities []StreamQuality) int { + type IndexedQuality struct { + index int + quality StreamQuality + } + + if len(qualities) < 2 { + return 0 + } + + indexedQualities := make([]IndexedQuality, 0) + for index, quality := range qualities { + indexedQuality := IndexedQuality{index, quality} + indexedQualities = append(indexedQualities, indexedQuality) + } + + sort.Slice(indexedQualities, func(a, b int) bool { + if indexedQualities[a].quality.IsVideoPassthrough && !indexedQualities[b].quality.IsVideoPassthrough { + return true + } + + if !indexedQualities[a].quality.IsVideoPassthrough && indexedQualities[b].quality.IsVideoPassthrough { + return false + } + + return indexedQualities[a].quality.VideoBitrate > indexedQualities[b].quality.VideoBitrate + }) + + return indexedQualities[0].index +} diff --git a/core/ffmpeg/thumbnailGenerator.go b/core/ffmpeg/thumbnailGenerator.go index bea74d469..5c7ec054c 100644 --- a/core/ffmpeg/thumbnailGenerator.go +++ b/core/ffmpeg/thumbnailGenerator.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os/exec" "path" + "strconv" "strings" "time" @@ -13,7 +14,7 @@ import ( ) //StartThumbnailGenerator starts generating thumbnails -func StartThumbnailGenerator(chunkPath string) { +func StartThumbnailGenerator(chunkPath string, variantIndex int) { // Every 20 seconds create a thumbnail from the most // recent video segment. ticker := time.NewTicker(20 * time.Second) @@ -23,7 +24,7 @@ func StartThumbnailGenerator(chunkPath string) { for { select { case <-ticker.C: - if err := fireThumbnailGenerator(chunkPath); err != nil { + if err := fireThumbnailGenerator(chunkPath, variantIndex); err != nil { log.Errorln("Unable to generate thumbnail:", err) } case <-quit: @@ -36,11 +37,11 @@ func StartThumbnailGenerator(chunkPath string) { }() } -func fireThumbnailGenerator(chunkPath string) error { +func fireThumbnailGenerator(chunkPath string, variantIndex int) error { // JPG takes less time to encode than PNG outputFile := path.Join("webroot", "thumbnail.jpg") - framePath := path.Join(chunkPath, "0") + framePath := path.Join(chunkPath, strconv.Itoa(variantIndex)) files, err := ioutil.ReadDir(framePath) if err != nil { return err diff --git a/core/status.go b/core/status.go index 8f7a34a50..d7c1c535b 100644 --- a/core/status.go +++ b/core/status.go @@ -39,7 +39,7 @@ func SetStreamAsConnected() { chunkPath = config.Config.PrivateHLSPath } - ffmpeg.StartThumbnailGenerator(chunkPath) + ffmpeg.StartThumbnailGenerator(chunkPath, config.Config.VideoSettings.HighestQualityStreamIndex) } //SetStreamAsDisconnected sets the stream as disconnected