Preview generation fallback (#725)

* Added preview generation fallback feature.
When a preview generation fails (often for wmv/avi files), the new code tries with less stricted (no xerror) and more time consuming options (slow+fast seek).
Fix a minor issue when stash downloads ffmpeg/ffprobe, but doesn't re-detect their paths.
This commit is contained in:
JoeSmithStarkers 2020-08-17 09:21:58 +10:00 committed by GitHub
parent 44c32a91d3
commit ecc42e4e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 14 deletions

4
.gitignore vendored
View File

@ -48,6 +48,9 @@ ui/v2.5/src/core/generated-*.tsx
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Goland Junk
pkg/pkg
####
# Random
####
@ -58,3 +61,4 @@ node_modules
stash
dist
.DS_Store

View File

@ -14,12 +14,51 @@ type ScenePreviewChunkOptions struct {
OutputPath string
}
func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePreviewChunkOptions, preset string) {
func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePreviewChunkOptions, preset string, fallback bool) error {
var fastSeek float64
var slowSeek float64
fallbackMinSlowSeek := 20.0
args := []string{
"-v", "error",
"-xerror",
"-ss", strconv.FormatFloat(options.StartTime, 'f', 2, 64),
"-i", probeResult.Path,
}
// Non-fallback: enable xerror.
// "-xerror" causes ffmpeg to fail on warnings, often the preview is fine but could be broken.
if !fallback {
args = append(args, "-xerror")
fastSeek = options.StartTime
slowSeek = 0
} else {
// In fallback mode, disable "-xerror" and try a combination of fast/slow seek instead of just fastseek
// Commonly with avi/wmv ffmpeg doesn't seem to always predict the right start point to begin decoding when
// using fast seek. If you force ffmpeg to decode more, it avoids the "blocky green artifact" issue.
if options.StartTime > fallbackMinSlowSeek {
// Handle seeks longer than fallbackMinSlowSeek with fast/slow seeks
// Allow for at least fallbackMinSlowSeek seconds of slow seek
fastSeek = options.StartTime - fallbackMinSlowSeek
slowSeek = fallbackMinSlowSeek
} else {
// Handle seeks shorter than fallbackMinSlowSeek with only slow seeks.
slowSeek = options.StartTime
fastSeek = 0
}
}
if fastSeek > 0 {
args = append(args, "-ss")
args = append(args, strconv.FormatFloat(fastSeek, 'f', 2, 64))
}
args = append(args, "-i")
args = append(args, probeResult.Path)
if slowSeek > 0 {
args = append(args, "-ss")
args = append(args, strconv.FormatFloat(slowSeek, 'f', 2, 64))
}
args2 := []string{
"-t", strconv.FormatFloat(options.Duration, 'f', 2, 64),
"-max_muxing_queue_size", "1024", // https://trac.ffmpeg.org/ticket/6375
"-y",
@ -36,10 +75,14 @@ func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePre
"-strict", "-2",
options.OutputPath,
}
_, _ = e.run(probeResult, args)
finalArgs := append(args, args2...)
_, err := e.run(probeResult, finalArgs)
return err
}
func (e *Encoder) ScenePreviewVideoChunkCombine(probeResult VideoFile, concatFilePath string, outputPath string) {
func (e *Encoder) ScenePreviewVideoChunkCombine(probeResult VideoFile, concatFilePath string, outputPath string) error {
args := []string{
"-v", "error",
"-f", "concat",
@ -48,7 +91,8 @@ func (e *Encoder) ScenePreviewVideoChunkCombine(probeResult VideoFile, concatFil
"-c", "copy",
outputPath,
}
_, _ = e.run(probeResult, args)
_, err := e.run(probeResult, args)
return err
}
func (e *Encoder) ScenePreviewVideoToImage(probeResult VideoFile, width int, videoPreviewPath string, outputPath string) error {

View File

@ -21,7 +21,7 @@ func (e *Encoder) Screenshot(probeResult VideoFile, options ScreenshotOptions) e
"-v", options.Verbosity,
"-ss", fmt.Sprintf("%v", options.Time),
"-y",
"-i", probeResult.Path, // TODO: Wrap in quotes?
"-i", probeResult.Path,
"-vframes", "1",
"-q:v", fmt.Sprintf("%v", options.Quality),
"-vf", fmt.Sprintf("scale=%v:-1", options.Width),

View File

@ -62,8 +62,11 @@ func (g *PreviewGenerator) Generate() error {
}
if g.GenerateVideo {
if err := g.generateVideo(&encoder); err != nil {
return err
if err := g.generateVideo(&encoder, false); err != nil {
logger.Warnf("[generator] failed generating scene preview, trying fallback")
if err := g.generateVideo(&encoder, true); err != nil {
return err
}
}
}
if g.GenerateImage {
@ -90,7 +93,7 @@ func (g *PreviewGenerator) generateConcatFile() error {
return w.Flush()
}
func (g *PreviewGenerator) generateVideo(encoder *ffmpeg.Encoder) error {
func (g *PreviewGenerator) generateVideo(encoder *ffmpeg.Encoder, fallback bool) error {
outputPath := filepath.Join(g.OutputDirectory, g.VideoFilename)
outputExists, _ := utils.FileExists(outputPath)
if !g.Overwrite && outputExists {
@ -111,11 +114,15 @@ func (g *PreviewGenerator) generateVideo(encoder *ffmpeg.Encoder) error {
Width: 640,
OutputPath: chunkOutputPath,
}
encoder.ScenePreviewVideoChunk(g.Info.VideoFile, options, g.PreviewPreset)
if err := encoder.ScenePreviewVideoChunk(g.Info.VideoFile, options, g.PreviewPreset, fallback); err != nil {
return err
}
}
videoOutputPath := filepath.Join(g.OutputDirectory, g.VideoFilename)
encoder.ScenePreviewVideoChunkCombine(g.Info.VideoFile, g.getConcatFilePath(), videoOutputPath)
if err := encoder.ScenePreviewVideoChunkCombine(g.Info.VideoFile, g.getConcatFilePath(), videoOutputPath); err != nil {
return err
}
logger.Debug("created video preview: ", videoOutputPath)
return nil
}

View File

@ -145,10 +145,12 @@ The FFMPEG and FFProbe binaries should be placed in %s
The error was: %s
`
logger.Fatalf(msg, configDirectory, err)
} else {
// After download get new paths for ffmpeg and ffprobe
ffmpegPath, ffprobePath = ffmpeg.GetPaths(configDirectory)
}
}
// TODO: is this valid after download?
instance.FFMPEGPath = ffmpegPath
instance.FFProbePath = ffprobePath
}

View File

@ -19,6 +19,7 @@ const markup = `
* Add support for parent/child studios.
### 🎨 Improvements
* Make preview generation more fault-tolerant.
* Allow clearing of images and querying on missing images.
* Allow free-editing of scene movie number.
* Allow adding performers and studios from selectors.