Make audio stream optional for preview generation (#1454)

This commit is contained in:
bnkai
2021-06-11 08:01:32 +03:00
committed by GitHub
parent f843359ba3
commit f1786ad871
11 changed files with 59 additions and 7 deletions

View File

@@ -10,6 +10,7 @@ fragment ConfigGeneralData on ConfigGeneralResult {
calculateMD5 calculateMD5
videoFileNamingAlgorithm videoFileNamingAlgorithm
parallelTasks parallelTasks
previewAudio
previewSegments previewSegments
previewSegmentDuration previewSegmentDuration
previewExcludeStart previewExcludeStart

View File

@@ -47,6 +47,8 @@ input ConfigGeneralInput {
videoFileNamingAlgorithm: HashAlgorithm! videoFileNamingAlgorithm: HashAlgorithm!
"""Number of parallel tasks to start during scan/generate""" """Number of parallel tasks to start during scan/generate"""
parallelTasks: Int parallelTasks: Int
"""Include audio stream in previews"""
previewAudio: Boolean!
"""Number of segments in a preview file""" """Number of segments in a preview file"""
previewSegments: Int previewSegments: Int
"""Preview segment duration, in seconds""" """Preview segment duration, in seconds"""
@@ -116,6 +118,8 @@ type ConfigGeneralResult {
videoFileNamingAlgorithm: HashAlgorithm! videoFileNamingAlgorithm: HashAlgorithm!
"""Number of parallel tasks to start during scan/generate""" """Number of parallel tasks to start during scan/generate"""
parallelTasks: Int! parallelTasks: Int!
"""Include audio stream in previews"""
previewAudio: Boolean!
"""Number of segments in a preview file""" """Number of segments in a preview file"""
previewSegments: Int! previewSegments: Int!
"""Preview segment duration, in seconds""" """Preview segment duration, in seconds"""

View File

@@ -88,6 +88,9 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co
if input.ParallelTasks != nil { if input.ParallelTasks != nil {
c.Set(config.ParallelTasks, *input.ParallelTasks) c.Set(config.ParallelTasks, *input.ParallelTasks)
} }
c.Set(config.PreviewAudio, input.PreviewAudio)
if input.PreviewSegments != nil { if input.PreviewSegments != nil {
c.Set(config.PreviewSegments, *input.PreviewSegments) c.Set(config.PreviewSegments, *input.PreviewSegments)
} }

View File

@@ -62,6 +62,7 @@ func makeConfigGeneralResult() *models.ConfigGeneralResult {
CalculateMd5: config.IsCalculateMD5(), CalculateMd5: config.IsCalculateMD5(),
VideoFileNamingAlgorithm: config.GetVideoFileNamingAlgorithm(), VideoFileNamingAlgorithm: config.GetVideoFileNamingAlgorithm(),
ParallelTasks: config.GetParallelTasks(), ParallelTasks: config.GetParallelTasks(),
PreviewAudio: config.GetPreviewAudio(),
PreviewSegments: config.GetPreviewSegments(), PreviewSegments: config.GetPreviewSegments(),
PreviewSegmentDuration: config.GetPreviewSegmentDuration(), PreviewSegmentDuration: config.GetPreviewSegmentDuration(),
PreviewExcludeStart: config.GetPreviewExcludeStart(), PreviewExcludeStart: config.GetPreviewExcludeStart(),

View File

@@ -12,6 +12,7 @@ type ScenePreviewChunkOptions struct {
Duration float64 Duration float64
Width int Width int
OutputPath string OutputPath string
Audio bool
} }
func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePreviewChunkOptions, preset string, fallback bool) error { func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePreviewChunkOptions, preset string, fallback bool) error {
@@ -23,6 +24,17 @@ func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePre
"-v", "error", "-v", "error",
} }
argsAudio := []string{
"-c:a", "aac",
"-b:a", "128k",
}
if !options.Audio {
argsAudio = []string{
"-an",
}
}
// Non-fallback: enable xerror. // Non-fallback: enable xerror.
// "-xerror" causes ffmpeg to fail on warnings, often the preview is fine but could be broken. // "-xerror" causes ffmpeg to fail on warnings, often the preview is fine but could be broken.
if !fallback { if !fallback {
@@ -70,13 +82,12 @@ func (e *Encoder) ScenePreviewVideoChunk(probeResult VideoFile, options ScenePre
"-crf", "21", "-crf", "21",
"-threads", "4", "-threads", "4",
"-vf", fmt.Sprintf("scale=%v:-2", options.Width), "-vf", fmt.Sprintf("scale=%v:-2", options.Width),
"-c:a", "aac",
"-b:a", "128k",
"-strict", "-2", "-strict", "-2",
options.OutputPath,
} }
finalArgs := append(args, args2...) args3 := append(args, args2...)
args3 = append(args3, argsAudio...)
finalArgs := append(args3, options.OutputPath)
_, err := e.run(probeResult, finalArgs) _, err := e.run(probeResult, finalArgs)
return err return err

View File

@@ -56,14 +56,17 @@ const CalculateMD5 = "calculate_md5"
// should be used when generating and using generated files for scenes. // should be used when generating and using generated files for scenes.
const VideoFileNamingAlgorithm = "video_file_naming_algorithm" const VideoFileNamingAlgorithm = "video_file_naming_algorithm"
const PreviewPreset = "preview_preset"
const MaxTranscodeSize = "max_transcode_size" const MaxTranscodeSize = "max_transcode_size"
const MaxStreamingTranscodeSize = "max_streaming_transcode_size" const MaxStreamingTranscodeSize = "max_streaming_transcode_size"
const ParallelTasks = "parallel_tasks" const ParallelTasks = "parallel_tasks"
const parallelTasksDefault = 1 const parallelTasksDefault = 1
const PreviewPreset = "preview_preset"
const PreviewAudio = "preview_audio"
const previewAudioDefault = true
const PreviewSegmentDuration = "preview_segment_duration" const PreviewSegmentDuration = "preview_segment_duration"
const previewSegmentDurationDefault = 0.75 const previewSegmentDurationDefault = 0.75
@@ -403,6 +406,11 @@ func (i *Instance) GetParallelTasksWithAutoDetection() int {
return parallelTasks return parallelTasks
} }
func (i *Instance) GetPreviewAudio() bool {
viper.SetDefault(PreviewAudio, previewAudioDefault)
return viper.GetBool(PreviewAudio)
}
// GetPreviewSegments returns the amount of segments in a scene preview file. // GetPreviewSegments returns the amount of segments in a scene preview file.
func (i *Instance) GetPreviewSegments() int { func (i *Instance) GetPreviewSegments() int {
return viper.GetInt(PreviewSegments) return viper.GetInt(PreviewSegments)
@@ -560,7 +568,6 @@ func (i *Instance) GetMenuItems() []string {
} }
func (i *Instance) GetSoundOnPreview() bool { func (i *Instance) GetSoundOnPreview() bool {
viper.SetDefault(SoundOnPreview, false)
return viper.GetBool(SoundOnPreview) return viper.GetBool(SoundOnPreview)
} }
@@ -740,6 +747,7 @@ func (i *Instance) setDefaultValues() error {
viper.SetDefault(PreviewSegments, previewSegmentsDefault) viper.SetDefault(PreviewSegments, previewSegmentsDefault)
viper.SetDefault(PreviewExcludeStart, previewExcludeStartDefault) viper.SetDefault(PreviewExcludeStart, previewExcludeStartDefault)
viper.SetDefault(PreviewExcludeEnd, previewExcludeEndDefault) viper.SetDefault(PreviewExcludeEnd, previewExcludeEndDefault)
viper.SetDefault(SoundOnPreview, false)
viper.SetDefault(Database, i.GetDefaultDatabaseFilePath()) viper.SetDefault(Database, i.GetDefaultDatabaseFilePath())

View File

@@ -27,6 +27,8 @@ type GeneratorInfo struct {
ExcludeEnd string ExcludeEnd string
VideoFile ffmpeg.VideoFile VideoFile ffmpeg.VideoFile
Audio bool // used for preview generation
} }
func newGeneratorInfo(videoFile ffmpeg.VideoFile) (*GeneratorInfo, error) { func newGeneratorInfo(videoFile ffmpeg.VideoFile) (*GeneratorInfo, error) {

View File

@@ -113,6 +113,8 @@ func (g *PreviewGenerator) generateVideo(encoder *ffmpeg.Encoder, fallback bool)
logger.Warnf("[generator] Segment duration (%f) too short.Using 0.75 instead.", g.Info.ChunkDuration) logger.Warnf("[generator] Segment duration (%f) too short.Using 0.75 instead.", g.Info.ChunkDuration)
} }
includeAudio := g.Info.Audio
for i := 0; i < g.Info.ChunkCount; i++ { for i := 0; i < g.Info.ChunkCount; i++ {
time := offset + (float64(i) * stepSize) time := offset + (float64(i) * stepSize)
num := fmt.Sprintf("%.3d", i) num := fmt.Sprintf("%.3d", i)
@@ -124,6 +126,7 @@ func (g *PreviewGenerator) generateVideo(encoder *ffmpeg.Encoder, fallback bool)
Duration: durationSegment, Duration: durationSegment,
Width: 640, Width: 640,
OutputPath: chunkOutputPath, OutputPath: chunkOutputPath,
Audio: includeAudio,
} }
if err := encoder.ScenePreviewVideoChunk(g.Info.VideoFile, options, g.PreviewPreset, fallback); err != nil { if err := encoder.ScenePreviewVideoChunk(g.Info.VideoFile, options, g.PreviewPreset, fallback); err != nil {
return err return err

View File

@@ -5,6 +5,7 @@ import (
"github.com/stashapp/stash/pkg/ffmpeg" "github.com/stashapp/stash/pkg/ffmpeg"
"github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils" "github.com/stashapp/stash/pkg/utils"
) )
@@ -50,6 +51,7 @@ func (t *GeneratePreviewTask) Start(wg *sizedwaitgroup.SizedWaitGroup) {
generator.Info.ChunkDuration = *t.Options.PreviewSegmentDuration generator.Info.ChunkDuration = *t.Options.PreviewSegmentDuration
generator.Info.ExcludeStart = *t.Options.PreviewExcludeStart generator.Info.ExcludeStart = *t.Options.PreviewExcludeStart
generator.Info.ExcludeEnd = *t.Options.PreviewExcludeEnd generator.Info.ExcludeEnd = *t.Options.PreviewExcludeEnd
generator.Info.Audio = config.GetInstance().GetPreviewAudio()
if err := generator.Generate(); err != nil { if err := generator.Generate(); err != nil {
logger.Errorf("error generating preview: %s", err.Error()) logger.Errorf("error generating preview: %s", err.Error())

View File

@@ -8,6 +8,7 @@
* Added [DLNA server](/settings?tab=dlna). ([#1364](https://github.com/stashapp/stash/pull/1364)) * Added [DLNA server](/settings?tab=dlna). ([#1364](https://github.com/stashapp/stash/pull/1364))
### 🎨 Improvements ### 🎨 Improvements
* Add option to disable audio for generated previews. ([#1454](https://github.com/stashapp/stash/pull/1454))
* Prompt when leaving scene edit page with unsaved changes. ([#1429](https://github.com/stashapp/stash/pull/1429)) * Prompt when leaving scene edit page with unsaved changes. ([#1429](https://github.com/stashapp/stash/pull/1429))
* Make multi-set mode buttons more obvious in multi-edit dialog. ([#1435](https://github.com/stashapp/stash/pull/1435)) * Make multi-set mode buttons more obvious in multi-edit dialog. ([#1435](https://github.com/stashapp/stash/pull/1435))
* Filter modifiers and sort by options are now sorted alphabetically. ([#1406](https://github.com/stashapp/stash/pull/1406)) * Filter modifiers and sort by options are now sorted alphabetically. ([#1406](https://github.com/stashapp/stash/pull/1406))

View File

@@ -84,6 +84,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
GQL.HashAlgorithm | undefined GQL.HashAlgorithm | undefined
>(undefined); >(undefined);
const [parallelTasks, setParallelTasks] = useState<number>(0); const [parallelTasks, setParallelTasks] = useState<number>(0);
const [previewAudio, setPreviewAudio] = useState<boolean>(true);
const [previewSegments, setPreviewSegments] = useState<number>(0); const [previewSegments, setPreviewSegments] = useState<number>(0);
const [previewSegmentDuration, setPreviewSegmentDuration] = useState<number>( const [previewSegmentDuration, setPreviewSegmentDuration] = useState<number>(
0 0
@@ -149,6 +150,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
videoFileNamingAlgorithm: videoFileNamingAlgorithm:
(videoFileNamingAlgorithm as GQL.HashAlgorithm) ?? undefined, (videoFileNamingAlgorithm as GQL.HashAlgorithm) ?? undefined,
parallelTasks, parallelTasks,
previewAudio,
previewSegments, previewSegments,
previewSegmentDuration, previewSegmentDuration,
previewExcludeStart, previewExcludeStart,
@@ -194,6 +196,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
setVideoFileNamingAlgorithm(conf.general.videoFileNamingAlgorithm); setVideoFileNamingAlgorithm(conf.general.videoFileNamingAlgorithm);
setCalculateMD5(conf.general.calculateMD5); setCalculateMD5(conf.general.calculateMD5);
setParallelTasks(conf.general.parallelTasks); setParallelTasks(conf.general.parallelTasks);
setPreviewAudio(conf.general.previewAudio);
setPreviewSegments(conf.general.previewSegments); setPreviewSegments(conf.general.previewSegments);
setPreviewSegmentDuration(conf.general.previewSegmentDuration); setPreviewSegmentDuration(conf.general.previewSegmentDuration);
setPreviewExcludeStart(conf.general.previewExcludeStart); setPreviewExcludeStart(conf.general.previewExcludeStart);
@@ -656,6 +659,19 @@ export const SettingsConfigurationPanel: React.FC = () => {
not recommended. not recommended.
</Form.Text> </Form.Text>
</Form.Group> </Form.Group>
<Form.Group>
<Form.Check
id="preview-include-audio"
checked={previewAudio}
label="Include audio"
onChange={() => setPreviewAudio(!previewAudio)}
/>
<Form.Text className="text-muted">
Includes audio stream when generating previews.
</Form.Text>
</Form.Group>
<Form.Group id="preview-segments"> <Form.Group id="preview-segments">
<h6>Number of segments in preview</h6> <h6>Number of segments in preview</h6>
<Form.Control <Form.Control