mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 16:34:02 +01:00
Rather than passing a pointer to a waitgroup into task.Start(..) functions, handle the waitgroup.Done() at the callsite. This makes waitgroup handling local to its definition rather than it being spread out over multiple files. Tasks now simply execute, and the policy of waiting on them is handled by the caller.
111 lines
3.3 KiB
Go
111 lines
3.3 KiB
Go
package manager
|
|
|
|
import (
|
|
"github.com/stashapp/stash/pkg/ffmpeg"
|
|
"github.com/stashapp/stash/pkg/logger"
|
|
"github.com/stashapp/stash/pkg/manager/config"
|
|
"github.com/stashapp/stash/pkg/models"
|
|
"github.com/stashapp/stash/pkg/utils"
|
|
)
|
|
|
|
type GenerateTranscodeTask struct {
|
|
Scene models.Scene
|
|
Overwrite bool
|
|
fileNamingAlgorithm models.HashAlgorithm
|
|
}
|
|
|
|
func (t *GenerateTranscodeTask) Start() {
|
|
hasTranscode := HasTranscode(&t.Scene, t.fileNamingAlgorithm)
|
|
if !t.Overwrite && hasTranscode {
|
|
return
|
|
}
|
|
|
|
var container ffmpeg.Container
|
|
|
|
if t.Scene.Format.Valid {
|
|
container = ffmpeg.Container(t.Scene.Format.String)
|
|
} else { // container isn't in the DB
|
|
// shouldn't happen unless user hasn't scanned after updating to PR#384+ version
|
|
tmpVideoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path, false)
|
|
if err != nil {
|
|
logger.Errorf("[transcode] error reading video file: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
container = ffmpeg.MatchContainer(tmpVideoFile.Container, t.Scene.Path)
|
|
}
|
|
|
|
videoCodec := t.Scene.VideoCodec.String
|
|
audioCodec := ffmpeg.MissingUnsupported
|
|
if t.Scene.AudioCodec.Valid {
|
|
audioCodec = ffmpeg.AudioCodec(t.Scene.AudioCodec.String)
|
|
}
|
|
|
|
if ffmpeg.IsStreamable(videoCodec, audioCodec, container) {
|
|
return
|
|
}
|
|
|
|
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path, false)
|
|
if err != nil {
|
|
logger.Errorf("[transcode] error reading video file: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
sceneHash := t.Scene.GetHash(t.fileNamingAlgorithm)
|
|
outputPath := instance.Paths.Generated.GetTmpPath(sceneHash + ".mp4")
|
|
transcodeSize := config.GetInstance().GetMaxTranscodeSize()
|
|
options := ffmpeg.TranscodeOptions{
|
|
OutputPath: outputPath,
|
|
MaxTranscodeSize: transcodeSize,
|
|
}
|
|
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
|
|
|
|
if videoCodec == ffmpeg.H264 { // for non supported h264 files stream copy the video part
|
|
if audioCodec == ffmpeg.MissingUnsupported {
|
|
encoder.CopyVideo(*videoFile, options)
|
|
} else {
|
|
encoder.TranscodeAudio(*videoFile, options)
|
|
}
|
|
} else {
|
|
if audioCodec == ffmpeg.MissingUnsupported {
|
|
//ffmpeg fails if it trys to transcode an unsupported audio codec
|
|
encoder.TranscodeVideo(*videoFile, options)
|
|
} else {
|
|
encoder.Transcode(*videoFile, options)
|
|
}
|
|
}
|
|
|
|
if err := utils.SafeMove(outputPath, instance.Paths.Scene.GetTranscodePath(sceneHash)); err != nil {
|
|
logger.Errorf("[transcode] error generating transcode: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
logger.Debugf("[transcode] <%s> created transcode: %s", sceneHash, outputPath)
|
|
}
|
|
|
|
// return true if transcode is needed
|
|
// used only when counting files to generate, doesn't affect the actual transcode generation
|
|
// if container is missing from DB it is treated as non supported in order not to delay the user
|
|
func (t *GenerateTranscodeTask) isTranscodeNeeded() bool {
|
|
|
|
videoCodec := t.Scene.VideoCodec.String
|
|
container := ""
|
|
audioCodec := ffmpeg.MissingUnsupported
|
|
if t.Scene.AudioCodec.Valid {
|
|
audioCodec = ffmpeg.AudioCodec(t.Scene.AudioCodec.String)
|
|
}
|
|
|
|
if t.Scene.Format.Valid {
|
|
container = t.Scene.Format.String
|
|
}
|
|
|
|
if ffmpeg.IsStreamable(videoCodec, audioCodec, ffmpeg.Container(container)) {
|
|
return false
|
|
}
|
|
|
|
hasTranscode := HasTranscode(&t.Scene, t.fileNamingAlgorithm)
|
|
if !t.Overwrite && hasTranscode {
|
|
return false
|
|
}
|
|
return true
|
|
}
|