mirror of
https://github.com/stashapp/stash.git
synced 2026-05-09 05:05:29 +02:00
Adds a separate generationHardwareAcceleration config toggle that opts the preview, marker, transcode, and clip-thumbnail tasks into the existing HW pipeline. Generator methods take path/width/height primitives; the marker task only probes for HW when a video preview is actually requested. On NVENC: 8K/41min/15-marker scene goes from 8m to 5m; 1080p/9min with no markers 15s to 14s. Short 720p clips are slower. Reduce concurrent tasks if VRAM is limited.
131 lines
3.2 KiB
Go
131 lines
3.2 KiB
Go
package manager
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/stashapp/stash/pkg/fsutil"
|
|
"github.com/stashapp/stash/pkg/logger"
|
|
"github.com/stashapp/stash/pkg/models"
|
|
"github.com/stashapp/stash/pkg/scene/generate"
|
|
)
|
|
|
|
type GeneratePreviewTask struct {
|
|
Scene models.Scene
|
|
ImagePreview bool
|
|
|
|
Options generate.PreviewOptions
|
|
|
|
Overwrite bool
|
|
fileNamingAlgorithm models.HashAlgorithm
|
|
|
|
generator *generate.Generator
|
|
|
|
videoPreviewExists *bool
|
|
imagePreviewExists *bool
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) GetDescription() string {
|
|
return fmt.Sprintf("Generating preview for %s", t.Scene.Path)
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) Start(ctx context.Context) {
|
|
videoChecksum := t.Scene.GetHash(t.fileNamingAlgorithm)
|
|
|
|
if t.videoPreviewRequired() {
|
|
ffprobe := instance.FFProbe
|
|
videoFile, err := ffprobe.NewVideoFile(t.Scene.Path)
|
|
if err != nil {
|
|
logger.Errorf("error reading video file: %v", err)
|
|
return
|
|
}
|
|
|
|
if err := t.generateVideo(videoChecksum, videoFile.Path, videoFile.Width, videoFile.Height, videoFile.VideoStreamDuration, videoFile.FrameRate); err != nil {
|
|
logger.Errorf("error generating preview: %v", err)
|
|
logErrorOutput(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
if t.imagePreviewRequired() {
|
|
if err := t.generateWebp(videoChecksum); err != nil {
|
|
logger.Errorf("error generating preview webp: %v", err)
|
|
logErrorOutput(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) generateVideo(videoChecksum string, path string, width, height int, duration float64, frameRate float64) error {
|
|
useVsync2 := false
|
|
|
|
if frameRate <= 0.01 {
|
|
logger.Errorf("[generator] Video framerate very low/high (%f) most likely vfr so using -vsync 2", frameRate)
|
|
useVsync2 = true
|
|
}
|
|
|
|
if err := t.generator.PreviewVideo(context.TODO(), path, width, height, duration, videoChecksum, t.Options, false, useVsync2); err != nil {
|
|
logger.Warnf("[generator] failed generating scene preview, trying fallback")
|
|
if err := t.generator.PreviewVideo(context.TODO(), path, width, height, duration, videoChecksum, t.Options, true, useVsync2); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) generateWebp(videoChecksum string) error {
|
|
videoFilename := t.Scene.Path
|
|
return t.generator.PreviewWebp(context.TODO(), videoFilename, videoChecksum)
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) required() bool {
|
|
return t.videoPreviewRequired() || t.imagePreviewRequired()
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) videoPreviewRequired() bool {
|
|
if t.Scene.Path == "" {
|
|
return false
|
|
}
|
|
|
|
if t.Overwrite {
|
|
return true
|
|
}
|
|
|
|
sceneChecksum := t.Scene.GetHash(t.fileNamingAlgorithm)
|
|
if sceneChecksum == "" {
|
|
return false
|
|
}
|
|
|
|
if t.videoPreviewExists == nil {
|
|
videoExists, _ := fsutil.FileExists(instance.Paths.Scene.GetVideoPreviewPath(sceneChecksum))
|
|
t.videoPreviewExists = &videoExists
|
|
}
|
|
|
|
return !*t.videoPreviewExists
|
|
}
|
|
|
|
func (t *GeneratePreviewTask) imagePreviewRequired() bool {
|
|
if !t.ImagePreview {
|
|
return false
|
|
}
|
|
|
|
if t.Scene.Path == "" {
|
|
return false
|
|
}
|
|
|
|
if t.Overwrite {
|
|
return true
|
|
}
|
|
|
|
sceneChecksum := t.Scene.GetHash(t.fileNamingAlgorithm)
|
|
if sceneChecksum == "" {
|
|
return false
|
|
}
|
|
|
|
if t.imagePreviewExists == nil {
|
|
imageExists, _ := fsutil.FileExists(instance.Paths.Scene.GetWebpPreviewPath(sceneChecksum))
|
|
t.imagePreviewExists = &imageExists
|
|
}
|
|
|
|
return !*t.imagePreviewExists
|
|
}
|