2019-02-11 20:12:08 +00:00
|
|
|
package manager
|
|
|
|
|
|
|
|
import (
|
2020-11-25 01:45:10 +00:00
|
|
|
"github.com/remeh/sizedwaitgroup"
|
|
|
|
|
2019-02-14 23:42:52 +00:00
|
|
|
"github.com/stashapp/stash/pkg/ffmpeg"
|
|
|
|
"github.com/stashapp/stash/pkg/logger"
|
2019-11-04 21:38:33 +00:00
|
|
|
"github.com/stashapp/stash/pkg/manager/config"
|
2019-02-14 23:42:52 +00:00
|
|
|
"github.com/stashapp/stash/pkg/models"
|
2020-08-21 07:57:07 +00:00
|
|
|
"github.com/stashapp/stash/pkg/utils"
|
2019-02-11 20:12:08 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type GenerateTranscodeTask struct {
|
2020-08-06 01:21:14 +00:00
|
|
|
Scene models.Scene
|
|
|
|
Overwrite bool
|
|
|
|
fileNamingAlgorithm models.HashAlgorithm
|
2019-02-11 20:12:08 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 01:45:10 +00:00
|
|
|
func (t *GenerateTranscodeTask) Start(wg *sizedwaitgroup.SizedWaitGroup) {
|
2019-02-11 20:12:08 +00:00
|
|
|
defer wg.Done()
|
|
|
|
|
2020-08-06 01:21:14 +00:00
|
|
|
hasTranscode := HasTranscode(&t.Scene, t.fileNamingAlgorithm)
|
2020-07-19 01:59:18 +00:00
|
|
|
if !t.Overwrite && hasTranscode {
|
2019-02-11 20:12:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-04-09 22:38:34 +00:00
|
|
|
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
|
2021-01-07 00:38:30 +00:00
|
|
|
tmpVideoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path, false)
|
2020-04-09 22:38:34 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-07-23 01:56:08 +00:00
|
|
|
if ffmpeg.IsStreamable(videoCodec, audioCodec, container) {
|
2020-04-09 22:38:34 +00:00
|
|
|
return
|
|
|
|
}
|
2019-02-11 20:12:08 +00:00
|
|
|
|
2021-01-07 00:38:30 +00:00
|
|
|
videoFile, err := ffmpeg.NewVideoFile(instance.FFProbePath, t.Scene.Path, false)
|
2019-02-11 20:12:08 +00:00
|
|
|
if err != nil {
|
|
|
|
logger.Errorf("[transcode] error reading video file: %s", err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-08-06 01:21:14 +00:00
|
|
|
sceneHash := t.Scene.GetHash(t.fileNamingAlgorithm)
|
|
|
|
outputPath := instance.Paths.Generated.GetTmpPath(sceneHash + ".mp4")
|
2021-04-11 23:31:33 +00:00
|
|
|
transcodeSize := config.GetInstance().GetMaxTranscodeSize()
|
2019-02-11 20:12:08 +00:00
|
|
|
options := ffmpeg.TranscodeOptions{
|
2019-11-04 21:38:33 +00:00
|
|
|
OutputPath: outputPath,
|
|
|
|
MaxTranscodeSize: transcodeSize,
|
2019-02-11 20:12:08 +00:00
|
|
|
}
|
2019-03-23 14:56:59 +00:00
|
|
|
encoder := ffmpeg.NewEncoder(instance.FFMPEGPath)
|
2020-04-09 22:38:34 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 07:57:07 +00:00
|
|
|
if err := utils.SafeMove(outputPath, instance.Paths.Scene.GetTranscodePath(sceneHash)); err != nil {
|
2019-02-11 20:12:08 +00:00
|
|
|
logger.Errorf("[transcode] error generating transcode: %s", err.Error())
|
|
|
|
return
|
|
|
|
}
|
2020-04-09 22:38:34 +00:00
|
|
|
|
2020-08-06 01:21:14 +00:00
|
|
|
logger.Debugf("[transcode] <%s> created transcode: %s", sceneHash, outputPath)
|
2019-02-14 22:53:32 +00:00
|
|
|
}
|
2019-11-15 17:23:58 +00:00
|
|
|
|
2020-04-09 22:38:34 +00:00
|
|
|
// 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
|
2019-11-15 17:23:58 +00:00
|
|
|
func (t *GenerateTranscodeTask) isTranscodeNeeded() bool {
|
|
|
|
|
|
|
|
videoCodec := t.Scene.VideoCodec.String
|
2020-04-09 22:38:34 +00:00
|
|
|
container := ""
|
|
|
|
audioCodec := ffmpeg.MissingUnsupported
|
|
|
|
if t.Scene.AudioCodec.Valid {
|
|
|
|
audioCodec = ffmpeg.AudioCodec(t.Scene.AudioCodec.String)
|
|
|
|
}
|
2019-11-15 17:23:58 +00:00
|
|
|
|
2020-04-09 22:38:34 +00:00
|
|
|
if t.Scene.Format.Valid {
|
|
|
|
container = t.Scene.Format.String
|
|
|
|
}
|
|
|
|
|
2020-07-23 01:56:08 +00:00
|
|
|
if ffmpeg.IsStreamable(videoCodec, audioCodec, ffmpeg.Container(container)) {
|
2019-11-15 17:23:58 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-08-06 01:21:14 +00:00
|
|
|
hasTranscode := HasTranscode(&t.Scene, t.fileNamingAlgorithm)
|
2020-07-19 01:59:18 +00:00
|
|
|
if !t.Overwrite && hasTranscode {
|
2019-11-15 17:23:58 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|