Use cmap for thumbnails

This commit is contained in:
Zoe Roux 2024-02-19 14:27:51 +01:00
parent acedb77c07
commit ee3d8916ed
2 changed files with 39 additions and 62 deletions

View File

@ -187,9 +187,10 @@ func (h *Handler) GetInfo(c echo.Context) error {
} }
// Run extractors to have them in cache // Run extractors to have them in cache
src.Extract(ret.Path, sha, route) src.Extract(ret.Path, sha, route)
go h.thumbnails.ExtractThumbnail( go src.ExtractThumbnail(
ret.Path, ret.Path,
fmt.Sprintf("%s/thumbnails.png", route), route,
&sha,
) )
return c.JSON(http.StatusOK, ret) return c.JSON(http.StatusOK, ret)
} }
@ -265,9 +266,10 @@ func (h *Handler) GetThumbnails(c echo.Context) error {
return err return err
} }
out, err := h.thumbnails.ExtractThumbnail( out, err := src.ExtractThumbnail(
path, path,
fmt.Sprintf("%s/thumbnails.png", GetRoute(c)), GetRoute(c),
nil,
) )
if err != nil { if err != nil {
return err return err
@ -288,9 +290,10 @@ func (h *Handler) GetThumbnailsVtt(c echo.Context) error {
return err return err
} }
out, err := h.thumbnails.ExtractThumbnail( out, err := src.ExtractThumbnail(
path, path,
fmt.Sprintf("%s/thumbnails.png", GetRoute(c)), GetRoute(c),
nil,
) )
if err != nil { if err != nil {
return err return err
@ -301,7 +304,6 @@ func (h *Handler) GetThumbnailsVtt(c echo.Context) error {
type Handler struct { type Handler struct {
transcoder *src.Transcoder transcoder *src.Transcoder
thumbnails *src.ThumbnailsCreator
} }
func main() { func main() {
@ -316,7 +318,6 @@ func main() {
} }
h := Handler{ h := Handler{
transcoder: transcoder, transcoder: transcoder,
thumbnails: src.NewThumbnailsCreator(),
} }
e.GET("/direct", DirectStream) e.GET("/direct", DirectStream)

View File

@ -20,71 +20,47 @@ var default_interval = 10
// Setting this too high allows really long processing times. // Setting this too high allows really long processing times.
var max_numcaps = 150 var max_numcaps = 150
type ThumbnailsCreator struct { type Thumbnail struct {
created map[string]string ready sync.WaitGroup
running map[string]chan struct{} path string
lock sync.Mutex
} }
func NewThumbnailsCreator() *ThumbnailsCreator { var thumbnails = NewCMap[string, *Thumbnail]()
return &ThumbnailsCreator{
created: make(map[string]string), func ExtractThumbnail(path string, route string, sha *string) (string, error) {
running: make(map[string]chan struct{}), ret, _ := thumbnails.GetOrCreate(path, func() *Thumbnail {
} if sha == nil {
nsha, err := GetHash(path)
if err != nil {
return nil
}
sha = &nsha
}
ret := &Thumbnail{
path: fmt.Sprintf("%s/%s", Settings.Metadata, sha),
}
ret.ready.Add(1)
go extractThumbnail(path, ret.path, fmt.Sprintf("%s/thumbnails.png", route))
return ret
})
ret.ready.Wait()
return ret.path, nil
} }
func (t *ThumbnailsCreator) ExtractThumbnail(path string, name string) (string, error) { func extractThumbnail(path string, out string, name string) error {
t.lock.Lock()
defer t.lock.Unlock()
out, ok := t.created[path]
if ok {
return out, nil
}
wait, ok := t.running[path]
if ok {
t.lock.Unlock()
<-wait
t.lock.Lock()
out = t.created[path]
return out, nil
}
wait = make(chan struct{})
t.running[path] = wait
t.lock.Unlock()
out, err := extractThumbnail(path, name)
t.lock.Lock()
// this will be unlocked by the defer at the top of the function.
delete(t.running, path)
if err == nil {
t.created[path] = out
}
return out, err
}
func extractThumbnail(path string, name string) (string, error) {
defer printExecTime("extracting thumbnails for %s", path)() defer printExecTime("extracting thumbnails for %s", path)()
sha, err := GetHash(path)
if err != nil {
return "", err
}
out := fmt.Sprintf("%s/%s", Settings.Metadata, sha)
os.MkdirAll(out, 0o755) os.MkdirAll(out, 0o755)
sprite_path := fmt.Sprintf("%s/sprite.png", out) sprite_path := fmt.Sprintf("%s/sprite.png", out)
vtt_path := fmt.Sprintf("%s/sprite.vtt", out) vtt_path := fmt.Sprintf("%s/sprite.vtt", out)
if _, err := os.Stat(sprite_path); err == nil { if _, err := os.Stat(sprite_path); err == nil {
return out, nil return nil
} }
gen, err := screengen.NewGenerator(path) gen, err := screengen.NewGenerator(path)
if err != nil { if err != nil {
log.Printf("Error reading video file: %v", err) log.Printf("Error reading video file: %v", err)
return "", err return err
} }
defer gen.Close() defer gen.Close()
@ -115,7 +91,7 @@ func extractThumbnail(path string, name string) (string, error) {
img, err := gen.ImageWxH(int64(ts*1000), width, height) img, err := gen.ImageWxH(int64(ts*1000), width, height)
if err != nil { if err != nil {
log.Printf("Could not generate screenshot %s", err) log.Printf("Could not generate screenshot %s", err)
return "", err return err
} }
x := (i % columns) * width x := (i % columns) * width
@ -138,13 +114,13 @@ func extractThumbnail(path string, name string) (string, error) {
err = os.WriteFile(vtt_path, []byte(vtt), 0o644) err = os.WriteFile(vtt_path, []byte(vtt), 0o644)
if err != nil { if err != nil {
return "", err return err
} }
err = imaging.Save(sprite, sprite_path) err = imaging.Save(sprite, sprite_path)
if err != nil { if err != nil {
return "", err return err
} }
return out, nil return nil
} }
func tsToVttTime(ts int) string { func tsToVttTime(ts int) string {