From 9ebec675b58164b4cbd8b033cf95610ca9005b86 Mon Sep 17 00:00:00 2001 From: Gabe Kangas Date: Wed, 10 Jun 2020 01:16:17 -0700 Subject: [PATCH] Generate a static thumbnail png every 20s --- main.go | 8 +++-- thumbnailGenerator.go | 72 +++++++++++++++++++++++++++++++++++++++++++ webroot/index.html | 4 +-- 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 thumbnailGenerator.go diff --git a/main.go b/main.go index 53fd219ce..6c4e816b4 100644 --- a/main.go +++ b/main.go @@ -13,14 +13,13 @@ var configuration = getConfig() var server *Server var online = false +var usingExternalStorage = false func main() { log.Println("Starting up. Please wait...") resetDirectories(configuration) checkConfig(configuration) - var usingExternalStorage = false - if configuration.IPFS.Enabled { storage = &IPFSStorage{} usingExternalStorage = true @@ -66,6 +65,11 @@ func getStatus(w http.ResponseWriter, r *http.Request) { func streamConnected() { online = true + chunkPath := configuration.PublicHLSPath + if usingExternalStorage { + chunkPath = configuration.PrivateHLSPath + } + startThumbnailGenerator(chunkPath) } func streamDisconnected() { diff --git a/thumbnailGenerator.go b/thumbnailGenerator.go new file mode 100644 index 000000000..3de76b3bf --- /dev/null +++ b/thumbnailGenerator.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "time" +) + +func startThumbnailGenerator(chunkPath string) { + // Every 20 seconds create a thumbnail from the most + // recent video segment. + ticker := time.NewTicker(20 * time.Second) + quit := make(chan struct{}) + go func() { + for { + select { + case <-ticker.C: + fireThumbnailGenerator(chunkPath) + case <-quit: + ticker.Stop() + return + } + } + }() +} + +func fireThumbnailGenerator(chunkPath string) { + framePath := path.Join(chunkPath, "0") + files, err := ioutil.ReadDir(framePath) + outputFile := path.Join("webroot", "thumbnail.png") + + // fmt.Println("Generating thumbnail from", framePath, "to", outputFile) + + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + var modTime time.Time + var names []string + for _, fi := range files { + if path.Ext(fi.Name()) != ".ts" { + continue + } + + if fi.Mode().IsRegular() { + if !fi.ModTime().Before(modTime) { + if fi.ModTime().After(modTime) { + modTime = fi.ModTime() + names = names[:0] + } + names = append(names, fi.Name()) + } + } + } + + if len(names) == 0 { + return + } + + mostRecentFile := path.Join(framePath, names[0]) + + ffmpegCmd := "ffmpeg -y -i " + mostRecentFile + " -ss 00:00:01.000 -vframes 1 " + outputFile + + // fmt.Println(ffmpegCmd) + + _, err = exec.Command("sh", "-c", ffmpegCmd).Output() + verifyError(err) +} diff --git a/webroot/index.html b/webroot/index.html index 4663ac23e..4ff89b8d1 100644 --- a/webroot/index.html +++ b/webroot/index.html @@ -31,10 +31,10 @@ id="video" class="video-js vjs-theme-fantasy" preload="auto" - poster="https://picsum.photos/900/600" + poster="/thumbnail.png" autoplay controls - style="width: 100%;" + style="width: 100%; height: 600px;" data-setup='{}' >